在创建NSManagedObject
的扩展帮助程序以创建新的托管对象子类时,swift提供Self
类型来模仿instancetype
这很好,但我似乎无法进行类型转换来自AnyObject
。以下代码无法编译,错误'AnyObject'无法转换为'Self'
帮助?
extension NSManagedObject
{
class func createInContext(context:NSManagedObjectContext) -> Self {
var classname = className()
var object: AnyObject = NSEntityDescription.insertNewObjectForEntityForName(classname, inManagedObjectContext: context)
return object
}
class func className() -> String {
let classString = NSStringFromClass(self)
//Remove Swift module name
let range = classString.rangeOfString(".", options: NSStringCompareOptions.CaseInsensitiveSearch, range: Range<String.Index>(start:classString.startIndex, end: classString.endIndex), locale: nil)
return classString.substringFromIndex(range!.endIndex)
}
}
答案 0 :(得分:26)
(现已更新为Swift 3/4。早期Swift版本的解决方案 可以在编辑历史中找到。)
您可以使用unsafeDowncast
来转换返回值
NSEntityDescription.insertNewObject()
到Self
(实际调用该方法的类型):
extension NSManagedObject {
class func create(in context: NSManagedObjectContext) -> Self {
let classname = entityName()
let object = NSEntityDescription.insertNewObject(forEntityName: classname, into: context)
return unsafeDowncast(object, to: self)
}
// Returns the unqualified class name, i.e. the last component.
// Can be overridden in a subclass.
class func entityName() -> String {
return String(describing: self)
}
}
然后
let obj = YourEntity.createInContext(context)
有效,编译器将obj
的类型正确推断为YourEntity
。
答案 1 :(得分:9)
通过实施,这是一种解决问题的不同方法 初始值设定项方法(使用Xcode 7.1测试):
extension NSManagedObject {
// Returns the unqualified class name, i.e. the last component.
// Can be overridden in a subclass.
class func entityName() -> String {
return String(self)
}
convenience init(context: NSManagedObjectContext) {
let eName = self.dynamicType.entityName()
let entity = NSEntityDescription.entityForName(eName, inManagedObjectContext: context)!
self.init(entity: entity, insertIntoManagedObjectContext: context)
}
}
Init方法的隐式返回类型为Self
且没有强制转换
技巧是必要的。
let obj = YourEntity(context: context)
创建YourEntity
类型的对象。
Swift 3/4更新:
extension NSManagedObject {
// Returns the unqualified class name, i.e. the last component.
// Can be overridden in a subclass.
class func entityName() -> String {
return String(describing: self)
}
convenience init(context: NSManagedObjectContext) {
let eName = type(of: self).entityName()
let entity = NSEntityDescription.entity(forEntityName: eName, in: context)!
self.init(entity: entity, insertInto: context)
}
}
答案 2 :(得分:4)
在Swift 2中,有一个使用协议和协议扩展的非常智能的解决方案
protocol Fetchable
{
typealias FetchableType: NSManagedObject
static var entityName : String { get }
static func createInContext(context: NSManagedObjectContext) -> FetchableType
}
extension Fetchable where Self : NSManagedObject, FetchableType == Self
{
static func createInContext(context: NSManagedObjectContext) -> FetchableType
{
return NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext: context) as! FetchableType
}
}
在每个NSManagedObject
子类中添加协议Fetchable
并实现属性entityName
。
现在函数MyEntity.createInContext(…)
将返回正确的类型而无需进一步的类型转换。