Il trucco è quello di utilizzare un metodo di supporto generico che deduce il tipo di self
dal contesto. Il tuo metodo className()
può anche essere semplificato un po ', e un nome migliore potrebbe da entityName()
:
extension NSManagedObject
{
class func createInContext(context:NSManagedObjectContext) -> Self {
return createInContextHelper(context)
}
private class func createInContextHelper<T>(context:NSManagedObjectContext) -> T {
let classname = entityName()
let object = NSEntityDescription.insertNewObjectForEntityForName(classname, inManagedObjectContext: context) as! T
return object
}
class func entityName() -> String {
let classString = NSStringFromClass(self)
// The entity is the last component of dot-separated class name:
let components = split(classString, { $0 == "." })
return components.last ?? classString
}
}
Poi
let obj = YourEntity.createInContext(context)
opere e il compilatore deduce il tipo di obj
correttamente come YourEntity
.
Aggiornamento: Utilizzando le idee da How to use generic types to get object with same type, questo può essere fatto anche con una funzione riutilizzabile globale invece del metodo di supporto al cast del valore restituito al tipo appropriato:
func objcast<T>(obj: AnyObject) -> T {
return obj as T
}
extension NSManagedObject
{
class func createInContext(context:NSManagedObjectContext) -> Self {
let classname = entityName()
let object: AnyObject = NSEntityDescription.insertNewObjectForEntityForName(classname, inManagedObjectContext: context)
return objcast(object)
}
class func entityName() -> String {
let classString = NSStringFromClass(self)
// The entity is the last component of dot-separated class name:
let components = split(classString, { $0 == "." })
return components.last ?? classString
}
}
Aggiornamento per Swift 1.2/Xcode 6.3 e Swift 2/Xcode 7:
func objcast<T>(obj: AnyObject) -> T {
return obj as! T
}
extension NSManagedObject
{
class func createInContext(context:NSManagedObjectContext) -> Self {
let classname = entityName()
let object: AnyObject = NSEntityDescription.insertNewObjectForEntityForName(classname, inManagedObjectContext: context)
return objcast(object)
}
class func entityName() -> String {
let classString = NSStringFromClass(self)
// The entity is the last component of dot-separated class name:
let components = classString.componentsSeparatedByString(".")
return components.last ?? classString
}
}
O con unsafeBitCast
invece di un metodo di supporto, come suggerito nei commenti:
extension NSManagedObject
{
class func createInContext(context:NSManagedObjectContext) -> Self {
let classname = entityName()
let object: AnyObject = NSEntityDescription.insertNewObjectForEntityForName(classname, inManagedObjectContext: context)
return unsafeBitCast(object, self)
}
class func entityName() -> String {
let classString = NSStringFromClass(self)
// The entity is the last component of dot-separated class name:
let components = classString.componentsSeparatedByString(".")
return components.last ?? classString
}
}
fonte
2014-11-24 19:13:27
2 ¢: Quella funzione generica è un caso di utilizzo piuttosto buono per la parola chiave 'private'. – Mazyod
@Mazyod: buon suggerimento, fatto. –
In Swift 2, split non è più una funzione globale. Possiamo invece utilizzare classString.componentsSeparatedByString ("."). –