为什么访问具有父关系的子类 NSManagedObject 的字符串参数会崩溃?
Why does accessing a String parameter of a subclassed NSManagedObject with a parent relationship crash?
我已经为两个核心数据实体生成了 classes。第一个称为地址,是一个抽象实体。第二个称为 Person,它继承自 Address。出于此测试的目的,我添加了一些示例托管属性。而且我已经向 Person class 添加了一个非托管字符串 属性。访问 Person class 的字符串 属性 会崩溃。为什么会崩溃?
Address 和 Person classes 由 Xcode 自动生成,除了额外的参数:let foo = "Foo"
如果我修改代码使 Person 直接从 NSManagedObject 继承而不是 Address,那么代码可以工作并且不会崩溃。
自动生成地址class:
@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?
}
自动生成的人 class,"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"
然后打印语句不会崩溃,而是将值解释为 'nil' 并打印出来。
所以我的问题变成了:为什么这个作为常量赋值的值在幕后被重置为 nil?
我有两个挥手解释为什么你得到零:
- 托管对象只有在插入后才能很好地发挥作用。
- 您的
foo
是一个我称之为 存储的常量 属性。我编造了这个名字,因为红旗,我在 Swift book chapter on Properties 中找不到任何例子
将这两个放在一起,你会得到一个不起作用的边缘情况。
话虽这么说,我有点惊讶您的 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
。
我已经为两个核心数据实体生成了 classes。第一个称为地址,是一个抽象实体。第二个称为 Person,它继承自 Address。出于此测试的目的,我添加了一些示例托管属性。而且我已经向 Person class 添加了一个非托管字符串 属性。访问 Person class 的字符串 属性 会崩溃。为什么会崩溃?
Address 和 Person classes 由 Xcode 自动生成,除了额外的参数:let foo = "Foo"
如果我修改代码使 Person 直接从 NSManagedObject 继承而不是 Address,那么代码可以工作并且不会崩溃。
自动生成地址class:
@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?
}
自动生成的人 class,"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"
然后打印语句不会崩溃,而是将值解释为 'nil' 并打印出来。
所以我的问题变成了:为什么这个作为常量赋值的值在幕后被重置为 nil?
我有两个挥手解释为什么你得到零:
- 托管对象只有在插入后才能很好地发挥作用。
- 您的
foo
是一个我称之为 存储的常量 属性。我编造了这个名字,因为红旗,我在 Swift book chapter on Properties 中找不到任何例子
将这两个放在一起,你会得到一个不起作用的边缘情况。
话虽这么说,我有点惊讶您的 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
。