Reputation: 49
i have the following problem:
I create a NSManagedObject
func createRecord(participation: Participation, start: NSDate, course: Course?) -> Record {
let newRecord = NSEntityDescription.insertNewObjectForEntityForName("Record", inManagedObjectContext: bmoc) as! Record
newRecord.setValue(participation, forKey: "participation");
newRecord.setValue(start, forKey: "start");
newRecord.setValue(course, forKey: "course");
newRecord.setValue(0, forKey: "finished");
newRecord.setValue(0, forKey: "experience");
newRecord.setValue(false, forKey: "synced");
var err : NSError?
bmoc.save(&err)
if(err != nil) {
NSLog(err!.description)
}
return newRecord;
Then i use this object in a controller with a NSTimer that calls this
println(record!.start); labelTimer.setTime(NSDate().timeIntervalSinceDate(record!.start))
The Controller has these two methods defined to start and stop the timer. In AppDelegate those methods are called and work like expected.
func applicationWillResignActive(application: UIApplication) {
println("applicationWillResignActive")
trackingDelegate?.stopTimer()
}
func applicationDidBecomeActive(application: UIApplication) {
println("applicationDidBecomeActive")
trackingDelegate?.startTimer()
}
The basic idea is to have a timer the users starts with a button which calls startTimer() aswell. When the user closes the app with the home button, StopTimer() is called and works without any problems. When the app didBecomeActive, i get the following error at println(record!.start)
THREAD 1: EXC_BAD_ACCESS (code=1, address = 0x0)
Does anyone have an idea why? The Object is persistent. If i check the database with an sqlite-viewer, i see it.. When i try to access the other two objects participation and course in the controller directly with something like course.name, it works, record.course.name does not. Only the Record-Object seems to have a problem.
Runtime value of Record-Object:
Printing description of self.record:
(StudyTracker.Record?) record = 0x00007ff7a2ee3ea0 {
CoreData.NSManagedObject = {
NSManagedObject = {
NSObject = {
isa = StudyTracker.Record_Record_
}
_cd_rc = 4
_cd_stateFlags = 40667072
_cd_rawData = nil
_cd_entity = 0x00007ff7a2e74dd0
_cd_managedObjectContext = 0x00007ff7a2d2fbb0
_cd_objectID = 0xd00000000158000a
_cd_extraFlags = 104
_cd_observationInfo = nil
_cd_snapshots = 0x0000000000000000
_cd_lockingInfo = 0
_cd_queueReference = 0x00007ff7a2d4a490
}
}
}
Code for CoreData is the default one:
lazy var applicationDocumentsDirectory: NSURL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "de.unikassel.StudyTracker" in the application's documents Application Support directory.
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1] as! NSURL
}()
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
let modelURL = NSBundle.mainBundle().URLForResource("StudyTracker", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("StudyTracker.sqlite")
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil {
coordinator = nil
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(error), \(error!.userInfo)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext? = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
Best regards and thanks in advance, Christian
Upvotes: 0
Views: 444
Reputation: 49
Basicly using this context with concurrencyType MainQueueConcurrencyType when setting up coredata did also the trick, especially when working with a wiget later on.
var managedObjectContext = NSManagedObjectContext(concurrencyType:.MainQueueConcurrencyType)
Duncan's advice worked, but was somehow redundant when i had to change the context type due to sharing data with a widget.
Thanks for the help!
Upvotes: 1
Reputation: 8988
The timer will be calling your code on a different thread to the one you used to create the managedObject, so you will need to make sure you call the println(!record.start)
from the same thread, which is, presumably, the main thread. Something like this:
NSOperationQueue.mainQueue().addOperationWithBlock {
println(!record.start)
}
or
dispatch_async(dispatch_get_main_queue(), {
println(!record.start)
})
Upvotes: 0