我已经为两个核心数据实体生成了类。第一个叫做Address,是一个抽象的实体。第二个叫做Person,它继承自Address。我为此测试添加了一些示例托管属性。我已经为Person类添加了一个非托管的String属性。访问Person类的字符串属性将崩溃。为什么会崩溃?
Address和Person类由Xcode自动生成,但额外参数除外:let foo =“Foo”
如果我修改代码使Person直接从NSManagedObject继承而不是Address,那么代码可以正常工作并且不会崩溃。
自动生成的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)
更新:如果foo定义为
public let foo: String? = "Foo"
那么print语句不会崩溃,而是将值解释为'nil'并打印出来。
所以我的问题就变成了:为什么这个被赋值为常量的值被重置为nil?
我有两个挥手的解释为什么你得到零:
foo
是我所谓的恒定存储属性。我编造了这个名字,因为,红旗,我在Swift book chapter on Properties找不到它的任何例子把这两个放在一起,你得到一个不起作用的边缘情况。
话虽这么说,我有点惊讶你的foo
设置不起作用,因为foo
不是托管属性(也就是说,它不在数据模型中)。如果我在常规的非托管对象中创建这样的常量存储属性...
public class Animal {
public let foo: String! = "Foo"
}
它按预期稍后回读。
因此,如果您可以接受此边缘情况在Core Data中不起作用,您可以继续使用其他几种正常工作方式。
一种方法是将foo
声明为var
,并在awakeFromInsert()
中指定一个值,正如我之前提到的那样,在插入之后。在核心数据中,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
引用。