6

我有扩展名NSManagedObject应该可以帮助我在上下文之间传输对象:

extension NSManagedObject {

    func transferTo(#context: NSManagedObjectContext) -> NSManagedObject? {

        return context.objectWithID(objectID)
    }

}

现在它返回对象,NSManagedObject我应该将它转换为我想要的类,如下所示:

let someEntity: MyEntity = // ...create someEntity
let entity: MyEntity = someEntity.transferTo(context: newContext) as? MyEntity

有没有办法Swift避免这种无用的转换,如果我transferTo(context: ...)从类的对象调用MyEntity使其返回类型为MyEntity

4

3 回答 3

3

我很喜欢 Martin 的解决方案,但最近遇到了麻烦。如果对象已经被 KVO 观察到,那么这将崩溃。Self在这种情况下是 KVO 子类,而结果objectWithID不是该子类,因此您会遇到类似“无法将 'myapp.Thing' (0xdeadbeef) 类型的值转换为 'myapp.Thing' (0xfdfdfdfd) 的值”的崩溃。 " 有两个类调用自己myapp.Thing,并as!使用实际的类对象。所以 Swift 不会被 KVO 类的高贵谎言所愚弄。

Self解决方案是通过将其移动到上下文来替换为静态类型参数:

extension NSManagedObjectContext {
    func transferredObject<T: NSManagedObject>(object: T) -> T {
        return objectWithID(object.objectID) as! T
    }
}

T纯粹是在编译时定义的,所以即使objectT.

于 2016-06-14T15:41:15.310 回答
2

这可以解决问题:

func transferTo(#context: NSManagedObjectContext) -> Self?

在调用站点,Self解析为您正在调用此方法的对象的静态已知类型。当您不知道符合协议的最终类型但仍想引用它时,这在协议中使用也特别方便。

更新: Martin R 的回答指出您不能立即投射获得的对象。然后我会做这样的事情:

// top-level utility function
func cast<T>(obj: Any?, type: T.Type) -> T? {
    return obj as? T
}

extension NSManagedObject {

    func transferTo(#context: NSManagedObjectContext) -> NSManagedObject? {
        return cast(context.objectWithID(objectID), self.dynamicType)
    }

}
于 2015-01-30T10:12:37.907 回答
2

更新:有关更好的解决方案,请参阅Rob 的回答


与如何在 NSManagedObject Swift 扩展中创建托管对象子类的实例类似?,这可以通过一个通用的辅助方法来完成:

extension NSManagedObject {

    func transferTo(context context: NSManagedObjectContext) -> Self {
        return transferToHelper(context: context)
    }

    private func transferToHelper<T>(context context: NSManagedObjectContext) -> T {
        return context.objectWithID(objectID) as! T
    }
}

请注意,我已将返回类型更改为Self. objectWithID()不返回可选项(与 相比,因此此处无需返回可选项objectRegisteredForID()

更新: Jean-Philippe Pellet 建议 定义一个全局可重用函数而不是辅助方法来将返回值转换为适当的类型。

我建议定义两个(重载)版本,以使其适用于可选和非可选对象(没有不需要的自动包装到可选对象中):

func objcast<T>(obj: AnyObject) -> T {
    return obj as! T
}

func objcast<T>(obj: AnyObject?) -> T? {
    return obj as! T?
}

extension NSManagedObject {

    func transferTo(context context: NSManagedObjectContext) -> Self {
        let result = context.objectWithID(objectID) // NSManagedObject
        return objcast(result) // Self
    }

    func transferUsingRegisteredID(context context: NSManagedObjectContext) -> Self? {
        let result = context.objectRegisteredForID(objectID) // NSManagedObject?
        return objcast(result) // Self?
    }
}

(我已经更新了 Swift 2/Xcode 7 的代码。早期 Swift 版本的代码可以在编辑历史中找到。)

于 2015-01-30T10:24:13.933 回答