如何使用泛型类型获取相同类型的对象
How to use generic types to get object with same type
我有 NSManagedObject
的扩展,应该可以帮助我在上下文之间传输对象:
extension NSManagedObject {
func transferTo(#context: NSManagedObjectContext) -> NSManagedObject? {
return context.objectWithID(objectID)
}
}
目前它是 NSManagedObject
的 return 对象,我应该将它转换为 class 我想要的,像这样:
let someEntity: MyEntity = // ...create someEntity
let entity: MyEntity = someEntity.transferTo(context: newContext) as? MyEntity
在 Swift
中有没有办法避免这种无用的转换,如果我从 class MyEntity
的对象调用 transferTo(context: ...)
使其成为 return 类型到 MyEntity
?
这样做就可以了:
func transferTo(#context: NSManagedObjectContext) -> Self?
在调用站点,Self
解析为您调用此方法的对象的静态已知类型。当您不知道将符合协议但仍想引用它的最终类型时,这在协议中使用也特别方便。
Update: 指出获取到的对象不能马上投射。然后我会做这样的事情:
// 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)
}
}
更新: 更好的解决方案,参见。
与 How can I create instances of managed object subclasses in a NSManagedObject Swift extension? 类似,
这可以通过通用辅助方法完成:
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
}
}
请注意,我已将 return 类型更改为 Self
。
objectWithID()
不是 return 一个可选的
(与 objectRegisteredForID()
相反,所以不需要
return此处可选。
更新:
定义一个全局可重用函数而不是辅助方法
将 return 值转换为适当的类型。
我建议定义两个(重载的)版本,使这个
使用可选和非可选对象(没有不需要的
自动包装成可选的):
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 个版本可以在编辑历史中找到。)
我很喜欢 Martin 的解决方案很长时间了,但最近 运行 我遇到了麻烦。如果对象已经被 KVO 观察到,那么这将崩溃。 Self
在那种情况下是 KVO subclass,而 objectWithID
的结果不是那个 subclass,所以你会得到像 "Could not cast value of type 'myapp.Thing' (0xdeadbeef) to 'myapp.Thing' (0xfdfdfdfd)." 这样的崩溃有两个 class 称自己为 myapp.Thing
,as!
使用实际的 class 对象。所以 Swift 没有被 KVO classes.
的崇高谎言所愚弄
解决方案是将 Self
移动到上下文中,用静态类型参数替换:
extension NSManagedObjectContext {
func transferredObject<T: NSManagedObject>(object: T) -> T {
return objectWithID(object.objectID) as! T
}
}
T
纯粹是在编译时定义的,所以即使 object
是 T
.
的秘密子 class 也能正常工作
我有 NSManagedObject
的扩展,应该可以帮助我在上下文之间传输对象:
extension NSManagedObject {
func transferTo(#context: NSManagedObjectContext) -> NSManagedObject? {
return context.objectWithID(objectID)
}
}
目前它是 NSManagedObject
的 return 对象,我应该将它转换为 class 我想要的,像这样:
let someEntity: MyEntity = // ...create someEntity
let entity: MyEntity = someEntity.transferTo(context: newContext) as? MyEntity
在 Swift
中有没有办法避免这种无用的转换,如果我从 class MyEntity
的对象调用 transferTo(context: ...)
使其成为 return 类型到 MyEntity
?
这样做就可以了:
func transferTo(#context: NSManagedObjectContext) -> Self?
在调用站点,Self
解析为您调用此方法的对象的静态已知类型。当您不知道将符合协议但仍想引用它的最终类型时,这在协议中使用也特别方便。
Update:
// 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)
}
}
更新: 更好的解决方案,参见
与 How can I create instances of managed object subclasses in a NSManagedObject Swift extension? 类似, 这可以通过通用辅助方法完成:
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
}
}
请注意,我已将 return 类型更改为 Self
。
objectWithID()
不是 return 一个可选的
(与 objectRegisteredForID()
相反,所以不需要
return此处可选。
更新:
我建议定义两个(重载的)版本,使这个 使用可选和非可选对象(没有不需要的 自动包装成可选的):
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 个版本可以在编辑历史中找到。)
我很喜欢 Martin 的解决方案很长时间了,但最近 运行 我遇到了麻烦。如果对象已经被 KVO 观察到,那么这将崩溃。 Self
在那种情况下是 KVO subclass,而 objectWithID
的结果不是那个 subclass,所以你会得到像 "Could not cast value of type 'myapp.Thing' (0xdeadbeef) to 'myapp.Thing' (0xfdfdfdfd)." 这样的崩溃有两个 class 称自己为 myapp.Thing
,as!
使用实际的 class 对象。所以 Swift 没有被 KVO classes.
解决方案是将 Self
移动到上下文中,用静态类型参数替换:
extension NSManagedObjectContext {
func transferredObject<T: NSManagedObject>(object: T) -> T {
return objectWithID(object.objectID) as! T
}
}
T
纯粹是在编译时定义的,所以即使 object
是 T
.