Swift NSManagedObject 子类实现具有所需初始化协议的链接器错误
Swift linker error for NSManagedObject subclass implementing a protocol with a required init
我在开始的 Swift 项目中遇到问题。我使用 Alamofire 进行网络连接,使用 MagicalRecord 作为 Core Data 的包装器。我不知道这是否重要,但我还是要提一下。
设置
应用程序正在从 JSON API 中检索数据。使用 Alamofire's Generic Response Object Serialization 我创建了 Alamofire.Request
的扩展,如链接页面所示,并实现了以下协议:
@objc public protocol ResponseObjectSerializable {
init?(response: NSHTTPURLResponse, representation: AnyObject)
}
我创建的 class 看起来像这样:
final class Foo: ResponseObjectSerializable {
let bar: String
let baz: String
required init?(response: NSHTTPURLResponse, representation: AnyObject) {
self.bar = representation.valueForKeyPath("bar") as String
self.baz = representation.valueForKeyPath("baz") as String
}
}
要检索 JSON 数据并将其序列化为 Foo
,我只需执行以下操作:
Alamofire.request(.GET, "http://foo.com/api").responseObject { (_, _, foo: Foo?, _) in
println(foo.bar)
}
到目前为止,还不错。
问题:添加核心数据
问题是在我想添加 Core Data 功能时出现的。我想使用上述方法从 API 检索数据,序列化它并在某个时候使用 Core Data 保存它。
所以,我决定把上面的Foo
class调整成这样:
@objc(Foo)
final class Foo: NSManagedObject, ResponseObjectSerializable {
@NSManaged var bar: String
@NSManaged var baz: String
required init?(response: NSHTTPURLResponse, representation: AnyObject) {
self.bar = representation.valueForKeyPath("bar") as String
self.baz = representation.valueForKeyPath("baz") as String
}
}
那没用,因为 NSManagedObject
subclass 需要指定的初始化程序,所以我将 class 更改为:
@objc(Foo)
final class Foo: NSManagedObject, ResponseObjectSerializable {
@NSManaged var bar: String
@NSManaged var baz: String
convenience required init?(response: NSHTTPURLResponse, representation: AnyObject) {
let context = NSManagedObjectContext.defaultContext()
let entity = NSEntityDescription.entityForName("Foo", inManagedObjectContext: context)
self.init(entity: entity!, insertIntoManagedObjectContext: context)
self.bar = representation.valueForKeyPath("bar") as String
self.baz = representation.valueForKeyPath("baz") as String
}
}
错误
项目确实编译了,这看起来很有希望,但引发了以下错误:
Undefined symbols for architecture x86_64:
"__TFC7Project3Foo3barSS", referenced from:
TFC7Project3FoocfMS0_FT8responseCSo17NSHTTPURLResponse14representationPSs9AnyObject__GSqS0 in Foo.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我不知道为什么会导致该错误,我真的很想摆脱它。那么,有谁知道如何解决这个问题?感谢任何帮助。
我为什么要使用这种方法?
我的 iOS 应用程序中有搜索功能(在模式中)。搜索结果列为 Foo
个实例,但我没有在本地保存任何一个(目前)。这种方法只是一种方便的方式,可以在 UITableView 中轻松列出检索到的 JSON 数据。
一旦(从该列表中)选择了搜索结果,我想使用 Core Data 将该特定项目添加到本地数据库。只有那些保存的项目才会列在应用程序的主视图中。在我看来,使用相同的 class 似乎很方便。
我试过的(除了上面的)
在创建这个问题之前,我尝试 google 寻找一些解决方案(但可以找到任何可行的答案)并使用该站点上的搜索功能。我发现了几个(有些)相关的问题:
根据 this answer,我不得不使用 Xcode 6.3 beta,我试过 (6D543q)
,但也没有用。我目前正在使用 Xcode 6.2 (6C131e)
顺便说一句。
另一个似乎相关的问题有以下 answer。所以,我在变量声明中添加了 dynamic
:@NSManaged dynamic var bar: String
,但这也不起作用。
注释
我还想指出,我是 iOS(和 Swift)的新手,所以我可能没有使用正确的(或者我应该说推荐的)方法。如果是这种情况,请告诉我,以便我可以采取另一种可能不会导致此错误的方法。
由于我是 Swift 的新手,所以我没有意识到 __T
前缀字符串实际上是一个错位的 Swift 符号。当传递给 swift-demangle
工具时,它转换为:
__TFC7Project3Foo3barSS ---> Project.Foo.bar.setter : Swift.String
这显然意味着 setter 方法不存在。根据 this post,这是编译器中的错误。 @NSManaged
属性完全是动态的,因此托管属性根本不存在此函数,但 Swift 编译器的某些部分仍会生成使用它的代码。
同样的 post 描述了缺少的函数无论如何都不是真正需要的,因此我们可以通过向项目添加一个简单的 C 文件来欺骗编译器它的存在:
void _TFC7Project3Foo3barSS() {}
添加文件后,项目构建并运行良好,但它是一个 hack。因此,这是一个 解决方法 ,直到它在编译器中得到实际修复。
它被报告为雷达here。
我在开始的 Swift 项目中遇到问题。我使用 Alamofire 进行网络连接,使用 MagicalRecord 作为 Core Data 的包装器。我不知道这是否重要,但我还是要提一下。
设置
应用程序正在从 JSON API 中检索数据。使用 Alamofire's Generic Response Object Serialization 我创建了 Alamofire.Request
的扩展,如链接页面所示,并实现了以下协议:
@objc public protocol ResponseObjectSerializable {
init?(response: NSHTTPURLResponse, representation: AnyObject)
}
我创建的 class 看起来像这样:
final class Foo: ResponseObjectSerializable {
let bar: String
let baz: String
required init?(response: NSHTTPURLResponse, representation: AnyObject) {
self.bar = representation.valueForKeyPath("bar") as String
self.baz = representation.valueForKeyPath("baz") as String
}
}
要检索 JSON 数据并将其序列化为 Foo
,我只需执行以下操作:
Alamofire.request(.GET, "http://foo.com/api").responseObject { (_, _, foo: Foo?, _) in
println(foo.bar)
}
到目前为止,还不错。
问题:添加核心数据
问题是在我想添加 Core Data 功能时出现的。我想使用上述方法从 API 检索数据,序列化它并在某个时候使用 Core Data 保存它。
所以,我决定把上面的Foo
class调整成这样:
@objc(Foo)
final class Foo: NSManagedObject, ResponseObjectSerializable {
@NSManaged var bar: String
@NSManaged var baz: String
required init?(response: NSHTTPURLResponse, representation: AnyObject) {
self.bar = representation.valueForKeyPath("bar") as String
self.baz = representation.valueForKeyPath("baz") as String
}
}
那没用,因为 NSManagedObject
subclass 需要指定的初始化程序,所以我将 class 更改为:
@objc(Foo)
final class Foo: NSManagedObject, ResponseObjectSerializable {
@NSManaged var bar: String
@NSManaged var baz: String
convenience required init?(response: NSHTTPURLResponse, representation: AnyObject) {
let context = NSManagedObjectContext.defaultContext()
let entity = NSEntityDescription.entityForName("Foo", inManagedObjectContext: context)
self.init(entity: entity!, insertIntoManagedObjectContext: context)
self.bar = representation.valueForKeyPath("bar") as String
self.baz = representation.valueForKeyPath("baz") as String
}
}
错误
项目确实编译了,这看起来很有希望,但引发了以下错误:
Undefined symbols for architecture x86_64:
"__TFC7Project3Foo3barSS", referenced from:TFC7Project3FoocfMS0_FT8responseCSo17NSHTTPURLResponse14representationPSs9AnyObject__GSqS0 in Foo.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我不知道为什么会导致该错误,我真的很想摆脱它。那么,有谁知道如何解决这个问题?感谢任何帮助。
我为什么要使用这种方法?
我的 iOS 应用程序中有搜索功能(在模式中)。搜索结果列为 Foo
个实例,但我没有在本地保存任何一个(目前)。这种方法只是一种方便的方式,可以在 UITableView 中轻松列出检索到的 JSON 数据。
一旦(从该列表中)选择了搜索结果,我想使用 Core Data 将该特定项目添加到本地数据库。只有那些保存的项目才会列在应用程序的主视图中。在我看来,使用相同的 class 似乎很方便。
我试过的(除了上面的)
在创建这个问题之前,我尝试 google 寻找一些解决方案(但可以找到任何可行的答案)并使用该站点上的搜索功能。我发现了几个(有些)相关的问题:
根据 this answer,我不得不使用 Xcode 6.3 beta,我试过 (6D543q)
,但也没有用。我目前正在使用 Xcode 6.2 (6C131e)
顺便说一句。
另一个似乎相关的问题有以下 answer。所以,我在变量声明中添加了 dynamic
:@NSManaged dynamic var bar: String
,但这也不起作用。
注释
我还想指出,我是 iOS(和 Swift)的新手,所以我可能没有使用正确的(或者我应该说推荐的)方法。如果是这种情况,请告诉我,以便我可以采取另一种可能不会导致此错误的方法。
由于我是 Swift 的新手,所以我没有意识到 __T
前缀字符串实际上是一个错位的 Swift 符号。当传递给 swift-demangle
工具时,它转换为:
__TFC7Project3Foo3barSS ---> Project.Foo.bar.setter : Swift.String
这显然意味着 setter 方法不存在。根据 this post,这是编译器中的错误。 @NSManaged
属性完全是动态的,因此托管属性根本不存在此函数,但 Swift 编译器的某些部分仍会生成使用它的代码。
同样的 post 描述了缺少的函数无论如何都不是真正需要的,因此我们可以通过向项目添加一个简单的 C 文件来欺骗编译器它的存在:
void _TFC7Project3Foo3barSS() {}
添加文件后,项目构建并运行良好,但它是一个 hack。因此,这是一个 解决方法 ,直到它在编译器中得到实际修复。
它被报告为雷达here。