Reputation: 397
I have a NSOperation subclass that has its private context, and a singleton data manager class that has a context on main queue. All the UI and crud operation are done by this singleton class and a background fetch from cloud kit is done by the NSOperation subclass. Had few doubts as below.
Following is the code i have in NSoperation subclass.Can below code create deadlock?
self.localStoreMOC?.performBlockAndWait({ () -> Void in
//Long process of fetching data from cloud and pushing changes to cloud happens here.
var error:NSErrorPointer = nil
if self.localStoreMOC!.hasChanges
{
do
{
try self.localStoreMOC!.save()
}
catch let error1 as NSError
{
error.memory = error1
}
if error == nil
{
self.localStoreMOC!.parentContext!.performBlockAndWait({
do
{
try self.localStoreMOC!.parentContext!.save()
}
catch let error1 as NSError
{
print("wasSuccessful error1 \(error1)")
}
})
}
}
}
If i have a another singleton class using this class NSManagedOBject do i need to pass them though ID ?
Upvotes: 0
Views: 54
Reputation: 46728
First, you need to turn on -com.apple.CoreData.ConcurrencyDebug 1
in your run time arguments. That will help insure you are calling everything on the proper thread/queue.
Second, you are doing a lot of forced unwrapping of optionals, that is a very bad habit to be in. Best to unwrap them properly or use the optional unwrapping.
Third, what happens when you pause the debugger? Where is the line of code that it is pausing on and what queues are you on?
Just turning on the concurrency debug will most likely show you your issue.
If you are wanting to pass a reference to a NSManagedObject
from one context to another then yes, you need to use the NSManagedObjectID
as the NSManagedObject
is not safe to pass between contexts.
Was playing with the formatting a bit, the results may be of interest to you:
guard let local = localStoreMOC else { fatalError("Local store is nil") }
guard let parent = local.parentContext else { fatalError("Parent store is nil") }
local.performBlockAndWait {
//Long process of fetching data from cloud and pushing changes to cloud happens here.
if !local.hasChanges { return }
do {
try local.save()
parent.performBlockAndWait {
do {
try parent.save()
} catch {
print("wasSuccessful error1 \(error)")
}
}
} catch {
print("Failed to save local: \(error)")
}
}
This removes the forced unwrapping of optionals and prints both errors out if you get one in either case.
Also, some developers, say that nested performblockandwait like above will cause deadlock.
performBlockAndWait
will never cause a deadlock. It is more intelligent than that.
performBlockAndWait
then the call would effectively be a no-op and will NOT deadlockUpvotes: 1