When creating an extension helper to NSManagedObject
to create a new managed object subclass, swift provides the Self
type to mimic instancetype
which is great, but i can't seem to typecast from AnyObject
. The below code does not compile with error 'AnyObject' is not convertible to 'Self'
Help?
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)
}
}
From the Xcode menu bar, choose Editor > Create NSManagedObject Subclass. Select your data model, then the appropriate entity, and choose where to save the files. Xcode places both a class and a properties file into your project.
Most apps need just a single managed object context. The default configuration in most Core Data apps is a single managed object context associated with the main queue. Multiple managed object contexts make your apps harder to debug; it's not something you'd use in every app, in every situation.
A managed object context is an instance of NSManagedObjectContext . Its primary responsibility is to manage a collection of managed objects. These managed objects represent an internally consistent view of one or more persistent stores.
@NSManaged indicates that the variables will get some values when we run the app. Coredata automatically creates getter and setter for such props. It silences the compiler for warnings. NSmanaged is subclass of NSObject. @NSManaged means extra code will be given to these props at runtime.
(Updated for Swift 3/4 now. Solutions for earlier Swift versions can be found in the edit history.)
You can use unsafeDowncast
to cast the return value of NSEntityDescription.insertNewObject()
to Self
(which is the type on which the method is actually called):
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) } }
Then
let obj = YourEntity.createInContext(context)
works and the compiler infers the type of obj
correctly as YourEntity
.
In Swift 2 there is a very smart solution using a protocol and a protocol extension
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
}
}
In each NSManagedObject
subclass add the protocol Fetchable
and implement the property entityName
.
Now the function MyEntity.createInContext(…)
will return the proper type without further type casting.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With