Reputation: 181
To summarize what I've done:
Created a project named 2048.
Created a subclass of NSManagedObject
class BestScore: NSManagedObject {
@NSManaged var bestScoreModel: BestScoreModel
func update(score: Int) {
self.bestScoreModel!.score = score
}
}
Created a subclass of NSManagedObjectModel
class BestScoreModel: NSManagedObjectModel {
@NSManaged var score: Int
}
Created a Data Model under Core Data tab. Named the file as 2048.xcdatamodeld. Added an entity BestScoreModel with one attribute "score" and defined the type as Integer 16. Besides, I also updated the class of the entity as 2048.BestScoreModel according to the official document.
In the controller class, I added following variables
class HomeViewController: UIViewController {
var bestScore: BestScore?
@lazy var context: NSManagedObjectContext = {
let serviceName = NSBundle.mainBundle().infoDictionary.objectForKey("CFBundleName") as String
let modelURL = NSBundle.mainBundle().URLForResource(serviceName, withExtension: "momd")
let model = NSManagedObjectModel(contentsOfURL: modelURL)
if model == nil {
println("Error initilizing model from : \(modelURL)")
abort()
}
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let storeURL = (urls[urls.endIndex-1]).URLByAppendingPathComponent("\(serviceName).sqlite")
var error: NSError? = nil
var store = coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error)
if store == nil {
println("Failed to load store at \(storeURL) with error: \(error?.localizedDescription)")
abort()
}
var context = NSManagedObjectContext()
context.persistentStoreCoordinator = coordinator
return context
}()
override func viewDidLoad() {
super.viewDidLoad()
let entity: NSEntityDescription = NSEntityDescription.entityForName("BestScoreModel", inManagedObjectContext: context)
bestScore = BestScore(entity: entity, insertIntoManagedObjectContext: context)
bestScore.update(0)
}
}
The application was built successfully but when I ran the simulator, it threw exceptions with below
2014-07-13 00:56:59.944 2048[76600:4447122] -[NSManagedObject update:]: unrecognized selector sent to instance 0x10bc55d20
2014-07-13 00:56:59.948 2048[76600:4447122] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject update:]: unrecognized selector sent to instance 0x10bc55d20'
I'm completely new to iOS developing and have no experience before. I wanna take Swift as an opportunity for start writing apps without learning objective-c. Please let me know if I misconfigured anything.
Appreciate for your help.
PS: I get the implementation of the managed object context from here. Big thanks to the author!
Upvotes: 2
Views: 3110
Reputation: 3836
Try to specify module name for entity in your .xcdatamodeld
file. See Implementing Core Data Managed Object Subclasses section in "Using Swift with Cocoa and Objective-C (Swift 2.1)" book for detailed description were you can find it.
Upvotes: 0
Reputation: 539745
The NSManagedObjectModel
describes the collection of all entities used in your application, and there is usually no reason to subclass it.
I would suggest that you use the same name for both the entity and the corresponding managed object subclass. (This is also what Xcode does when you create an Objective-C managed object subclass)
The Swift managed object subclass (which Xcode cannot create automatically yet) would simply look like this:
class BestScore: NSManagedObject {
@NSManaged var score: NSNumber
}
I have used the NSNumber
type instead of Int16
, because scalar accessor methods in Swift managed
object subclasses do not yet work correctly, compare How to use Core Data Integer 64 with Swift Int64?.
A new BestScore object would then be created with
bestScore = NSEntityDescription.insertNewObjectForEntityForName("BestScore", inManagedObjectContext: context) as BestScore
and you can access its properties directly, without the need for an update()
function:
bestScore!.score = 0
Additional Remarks: It would make sense to define the bestScore
property as an
implicitly unwrapped optional, because you expect it to have a value after
viewDidLoad:
. That saves you many explicit unwrappings later:
var bestScore: BestScore!
Also, if the application is run a second time, you probably want to reload the existing best score, instead of creating a new object. That means that you have to execute a fetch request first, and insert a new object only if none was found:
let request = NSFetchRequest(entityName: "BestScore")
var error : NSError?
let result = context.executeFetchRequest(request, error: &error)
if !result || result.count == 0 {
// Error or no object found: create new one:
bestScore = NSEntityDescription.insertNewObjectForEntityForName("BestScore", inManagedObjectContext: context) as BestScore
bestScore.score = 0
} else {
// Use existing object:
bestScore = result[0] as BestScore
}
let score = bestScore.score.integerValue // NSNumber --> Integer
Upvotes: 2