Почему происходит сбой доступа к параметру String подкласса NSManagedObject с родительскими отношениями? - PullRequest
3 голосов
/ 30 марта 2019

Я создал классы для двух основных объектов данных. Первый называется Address и является абстрактной сущностью. Второй называется Person, и он наследуется от Address. Я добавил несколько примеров управляемых атрибутов для целей этого теста. И я добавил неуправляемое свойство String в класс Person. Доступ к строковому свойству класса Person приведет к сбою. Почему происходит сбой?

Классы Address и Person автоматически генерируются Xcode, за исключением дополнительного параметра: let foo = "Foo"

Если я изменю код, чтобы Person наследовал от NSManagedObject напрямую, а не от Address, тогда код работает и не падает.

Автоматически сгенерированный класс адресов:

@objc(Address)
public class Address: NSManagedObject {
}

extension Address {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Address> {
        return NSFetchRequest<Address>(entityName: "Address")
    }
    @NSManaged public var street: String?
    @NSManaged public var city: String?
}

Автоматически сгенерированный класс person, за исключением параметра "foo":

@objc(Person)
public class Person: Address {
    public let foo = "Foo"  //added this parameter
}

extension Person {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Person> {
        return NSFetchRequest<Person>(entityName: "Person")
    }
    @NSManaged public var name: String?
}

код проблемы

let person = Person(context: context)
print(person.foo) //doesn't crash, but prints empty line instead of value
print("VALUE:\(person.foo):") //crashes with Thread 1: EXC_BAD_ACCESS (code=1, address=0x18)

UPDATE: если foo определено как

public let foo: String? = "Foo"

тогда операторы print не аварийно завершают работу, вместо этого они интерпретируют значение как 'nil' и выводят его.

Итак, мой вопрос звучит так: почему это значение, которое присваивается как константа, сбрасывается на ноль под крышками?

1 Ответ

0 голосов
/ 31 марта 2019

У меня есть два объяснения, почему вы получаете ноль:

  • Управляемые объекты работают не очень хорошо, пока они не вставлены.
  • Ваш foo являетсячто я бы назвал постоянным хранимым свойством .Я придумал имя, потому что, красный флаг, я не могу найти никаких примеров этого в главе книги Swift по Свойства

Соедините эти два ивы получаете крайний случай, который не работает.

При этом я немного удивлен, что ваш параметр foo не работает, потому что foo не является управляемым свойством (то естьэто не в модели данных).Если я сделаю такое постоянное хранимое свойство в обычном неуправляемом объекте…

public class Animal {
    public let foo: String! = "Foo"
}

, оно будет считано позже, как и ожидалось.

Итак, если вы можетедопустим, что этот крайний случай просто не работает в Core Data, вы можете перейти к нескольким более обычным способам работы.

Один из способов - объявить foo как var и присвоить значение в awakeFromInsert(), которое, как я упоминал ранее, после вставки.В Core Data awakeFromInsert() является одним из ваших друзей ...

@objc(Person)
public class Person: Address {
    public var foo: String!
    override public func awakeFromInsert() {
        foo = "Foo"
    }
}

Еще один способ, который работает, это вычисляемое свойство ...

@objc(Person)
public class Person: Address {
    public var foo : String { return "Foo" }
}

И, наконец, самый логичный способ,Так как foo является константой для всех экземпляров, нужно сделать ее свойством типа

@objc(Person)
public class Person: Address {
    static var foo: String = "Foo"
}

, но, конечно, если вы делаете это, вы должны ссылаться на него как Person.foo вместо person.foo.

...