NSManagedObject子类的Swift链接器错误,实现具有所需init的协议

时间:2015-03-18 23:06:58

标签: ios swift core-data nsmanagedobject alamofire

我开始在Swift项目中遇到问题。我使用Alamofire进行网络连接,将MagicalRecord用作Core Data的包装器。我不知道这是否重要,但无论如何我都会提到它。

设置

应用程序正在从JSON API检索其数据。使用Alamofire's Generic Response Object Serialization我创建了Alamofire.Request的扩展名,可以在链接页面上看到,并实现了以下协议:

@objc public protocol ResponseObjectSerializable {
    init?(response: NSHTTPURLResponse, representation: AnyObject)
}

我创建的课程看起来像这样:

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)
}

到目前为止,非常好。

问题:添加核心数据

当我想添加核心数据功能时问题就出现了。我想使用上面的方法从API检索数据,序列化它,并在某些时候使用Core Data保存它。

所以,我决定将上面的Foo课程调整为:

@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子类需要指定的初始值设定项,所以我将我的类更改为:

@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
    }
}

错误

该项目确实编译,这似乎很有希望,但引发了以下错误:

  

架构x86_64的未定义符号:
  " __ TFC7Project3Foo3barSS",引自:

     Foo.o中的

TFC7Project3FoocfMS0_FT8responseCSo17NSHTTPURLResponse14representationPSs9AnyObject__GSqS0   ld:找不到架构x86_64的符号
  clang:错误:链接器命令失败,退出代码为1(使用-v查看调用)

我不知道它为什么会导致错误,我真的很想摆脱它。那么,有谁知道如何解决这个问题?任何帮助表示赞赏。

为什么我使用这种方法?

我的iOS应用程序中有搜索功能(在模态中)。搜索结果列为Foo个实例,但我还没有在本地保存任何实例。这种方法只是在UITableView中轻松列出检索到的JSON数据的一种方便方法。

一旦选择了搜索结果(从该列表中),我想使用Core Data将该特定项添加到本地数据库。只有那些保存的项目才会列在应用程序的主视图中。在我看来,使用相同的类似乎很方便。

我尝试过的(除上述内容外)

在创建此问题之前,我尝试谷歌寻找一些解决方案(但可以找到任何可行的答案)并使用此网站上的搜索功能。我发现了一些(有些)相关的问题:

根据this answer,我必须使用Xcode 6.3 beta,我已尝试(6D543q),但这也无效。我目前正在使用Xcode 6.2 (6C131e) btw。

另一个看似相关的问题是answer。所以,我在变量声明中添加了dynamic@NSManaged dynamic var bar: String,但这也不起作用。

备注

我还要注意我是iOS(和Swift)的新手,所以我可能没有使用正确的(或者我应该说推荐的)方法。如果是这种情况,请告诉我,以便我可以采取另一种可能不会导致此错误的方法。

1 个答案:

答案 0 :(得分:1)

由于我是Swift的新手,我没有意识到__T前缀字符串实际上是一个受损的Swift符号。传递给swift-demangle工具时,会转换为:

__TFC7Project3Foo3barSS ---> Project.Foo.bar.setter : Swift.String

这显然意味着setter方法不存在。根据{{​​3}}帖子,这是编译器中的一个错误。 @NSManaged属性完全是动态的,因此托管属性根本不存在此函数,但Swift编译器的某些部分仍会生成使用它的代码。

同一篇文章描述了无论如何都不需要丢失的函数,因此我们可以通过向项目中添加一个简单的C文件来欺骗编译器它的存在:

void _TFC7Project3Foo3barSS() {}

添加文件后,项目构建并运行正常,但它是 hack 。因此,这是一个解决方法,直到它在编译器中实际修复。

据报道它是雷达this