I thought that [moc existingObjectWithID:self.objectID error:&error]
was the right way to find an existing object inside of a thread, given its objectID
, but I can't get it to work, why?
I've got an NSManagedObject
which is already saved. I can see all its properties on the main thread. I'm passing the object to my NSOperation
in a custom init
method and in that method, I'm saving its objectID
:
- (instancetype)initWithEntity:(NSManagedObject *)object
{
self = [super init];
if (self) {
self.objectID = object.objectID;
...
}
return self;
}
Then in the main
function of my operation I'm looking up my object so that I can use it.
- (void)main
{
if (self.isCancelled) { return; }
NSManagedObjectContext *moc = [NSManagedObjectContext MR_context];
NSError *error = nil;
self.object = [moc existingObjectWithID:self.objectID error:&error];
if (error) {
DDLogError(@"error finding object: %@", error);
}
...
}
MR_context
is a MagicalRecord method which simply sets up a new context with concurrency type NSPrivateQueueConcurrencyType
with its parent set to the root saving context. All of that looks correct to me.
When no debugger is set, I simply get a fault
for the object. If I try to look up any property on it, I get nil
.
With the debugger turned on and -com.apple.CoreData.ConcurrencyDebug 1
set I get some errors:
In the simulator I get EXC_BAD_INSTRUCTION (code=EXC_i386_INVOP, subcode=0x0)
on the [moc existingObjectWithID:self.objectID error:&error]
line.
On the device, I get the following on that same line:
CoreData`+[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__]:
-> 0x185946614 <+0>: brk #0x1
So obviously something is wrong, but the objectID
isn't temporary, it is the same objectID
I see when inspecting the real object on the main thread. So I'm not sure why it isn't working.
I've also tried:
self.object = [moc objectWithID:self.objectID];
But that doesn't work either. Any ideas?
2015-07-10 - Ok, if I use a block with the moc
then I can properly access the object from within that block.
[moc performBlock:^{
NSError *error = nil;
NSManagedObject *o = [moc existingObjectWithID:self.objectID error:&error];
}];
How do I properly extract that object so I can have access to it in the thread that the operation is running? Doing a __block
property and then setting it in the block and using it out of the block failed.
Is this an issue with the way the context is setup?
MagicalRecord's context sets up its own queue to perform operations on it. Therefore, if you want to use it to look something up, you have to do it in a block ([context performBlock:]
or [context performBlockAndWait:]
) so that it can perform it on its own queue and then return back to the NSOperation
.
What I ended up doing was creating a couple __block
properties and then pulling the needed contents from the object outside of the block.