Имя подкласса NSManagedObject конфликтует с типом основания Swift - PullRequest
0 голосов
/ 06 августа 2020

Код, над которым я сейчас работаю (унаследованный от другой команды), имеет уровень сохраняемости, основанный на 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, которое отличается от модели.

Но нет, мое приложение вылетает если я внесу указанные выше изменения.

Есть ли способ обойти это, или я застрял с ужасным решением (и отсутствием предвидения) первоначального автора?

1 Ответ

1 голос
/ 06 августа 2020

Исходное состояние

Допустим, у вас есть следующий класс в Swift:

@objc(Notification)
class Notification: NSManagedObject {

}

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

extension Notification : Identifiable {
}

И в вашей модели следующий объект:

enter image description here

Change class name

Can I change class name? Sure. Just update your code:

@objc(MyNotification)
class MyNotification: NSManagedObject {
}

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

extension MyNotification : Identifiable {
}

И ваша модель:

enter image description here

It's important to keep the Entity Name set to Notification. There's no need for migration if you keep the Entity Name untouched.

Other comments

  • You should include the crash & stack trace in the question if it crashes after change like this one.
  • It's possible that it crashes because of another problem in the code.
  • I saw that people are still using className for entity name, which is utterly wrong, because NSManagedObject subclass class name can differ from the entity name. Perhaps, this is your problem? Don't know.
  • This is one of the reasons we have NSEntityDescription и name.
  • Также вы, наверное, заметили, что я использую Manual / None в Codegen . Это потому, что я хотел избежать любого вмешательства при генерации кода, когда я тестировал изменение имени класса.
  • Вы также можете изменить имя объекта, но тогда вам потребуется миграция.
...