Името на подкласа на NSManagedObject се сблъсква с типа на Swift Foundation

Кодът, върху който работя сега (наследен от друг екип), има слой за постоянство, базиран на CoreData.

Един от обектите се нарича „Известие“ и представлява съобщения, периодично анкетирани от клиентското приложение от задния край (несвързано с APS); съответният подклас NSManagedObject се дефинира по следния начин:

import Foundation
import CoreData

@objc(Notification) public class Notification: NSManagedObject {

    // etc...

Излишно е да казвам, че това име на клас засенчва едноименния тип Foundation (контрагент на NSNotification от страна на Objective-C). Приложението не използва техниката на NotificationCenter, така че досега не беше проблем.

Сега трябва да въведа известия за някои от моите класове, за да наблюдавам определени събития на ниво приложение и не искам да правя недвусмислие всеки път, напр.

let notification = Foundation.Notification.Name(...

Наясно съм, че не мога да променя имената на класовете на моите CoreData обекти, без да наруша съвместимостта, но си помислих, че @objc(Notification) ще ми позволи да променя името на класа Swift; например:

@objc(Notification) public class AppNotification: NSManagedObject {
//    ^ This stays the same      ^ This changes

...в крайна сметка CoreData е Objective-C API. Логично е, че ако трябва изрично да посоча името на мостовия клас на Objective-C, може би ще мога да се измъкна с име на клас Swift, което е различно от модела.

Но не, приложението ми се срива, ако направя промяната по-горе.

Има ли начин да се заобиколи това, или съм останал с ужасното решение (и липсата на предвидливост) на първоначалния автор?


person Nicolas Miari    schedule 06.08.2020    source източник
comment
Какво ще кажете за използването на typealias за Foundation.Notification?   -  person Sweeper    schedule 06.08.2020
comment
Великолепна идея. Сега трябва да измисля прилично и смислено име   -  person Nicolas Miari    schedule 06.08.2020
comment
за предпочитане е изобщо да се избягват сблъсъци на имена със стандартни имена на рамки, базирани на goal-c... все още е object-c по време на изпълнение и може да попаднете в много неочаквани и неясни проблеми по време на изпълнение. Така че просто направете имената си уникални и винаги ще сте сигурни кой кой е.   -  person Asperi    schedule 06.08.2020
comment
Донякъде имате късмет, защото @objc(Notification) не пречи на Foundation.Notification - референтният тип Obj-C е NSNotification. Както и да е, можете да промените името на класа (вижте моя отговор) и той не трябва да се срива. Ако се срине, има някои други проблеми във вашата кодова база, които са били скрити досега (като някой е използвал className, за да получи име на обект, ...). Или това може да е проблем с генерирането на код, стари извлечени данни, ... Включете проследяването на стека, за да можем да видим какво се случва.   -  person zrzka    schedule 06.08.2020


Отговори (1)


Първоначално състояние

Да приемем, че имате следния клас в Swift:

@objc(Notification)
class Notification: NSManagedObject {

}

extension Notification {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Notification> {
        return NSFetchRequest<Notification>(entityName: "Notification")
    }
}

extension Notification : Identifiable {
}

И следния обект във вашия модел:

въведете описание на изображението тук

Променете името на класа

Мога ли да променя името на класа? Сигурен. Просто актуализирайте кода си:

@objc(MyNotification)
class MyNotification: NSManagedObject {
}

extension MyNotification {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<MyNotification> {
        return NSFetchRequest<MyNotification>(entityName: "Notification")
    }
}

extension MyNotification : Identifiable {
}

И вашия модел:

въведете описание на изображението тук

Важно е името на обекта да е зададено на Известие. Няма нужда от мигриране, ако запазите името на обекта недокоснато.

Други коментари

  • Трябва да включите проследяването на срива и стека във въпроса, ако се срине след промяна като тази.
  • Възможно е да се срине поради друг проблем в кода.
  • Видях, че хората все още използват className за име на обект, което е крайно погрешно, защото името на класа на подклас NSManagedObject може да се различава от името на обекта. Може би това е вашият проблем? не знам
  • Това е една от причините да имаме NSEntityDescription & name.
  • Също така вероятно сте забелязали, че използвам Manual/None в Codegen. Това е така, защото исках да избегна намеса в генерирането на код, когато тествах промяната на името на класа.
  • Можете също да промените името на обекта, но тогава ще ви е необходима миграция.
person zrzka    schedule 06.08.2020
comment
Това е верният отговор. Имената на класовете Core Data не трябва да съвпадат с имена на обекти, въпреки че обикновено го правят. Промяната на името на класа няма ефект върху модела на данни и не изисква миграция. - person Tom Harrington; 06.08.2020