EXC_BAD_ACCESS on NSManagedObjectContext save method inside NSOperation and ARC, why? - objective-c

I have found some problems when saving NSManagedObjectContext inside NSOperation with turned on ARC. Without ARC everything was fine before. It is always gives EXC_BAD_ACCESS during saving. The code looks like this:
//on the main thread
-(void)someFunc
{
array = ... //fetching an array of entities from a core data
for(SomeEntity * obj in array)
{
NSSomeOperation * op = [[NSSomeOperation alloc] initWithValue:[obj someField]];
//start an operation
}
}
//NSSomeOperation implementation
//...
- (void)main {
//some code
NSError * error = nil;
[mainContext lock];
if (![mainContext save:&error]) { //<--- HERE EXC_BAD_ACCESS
//process error
}
[mainContext unlock];
//some code
}
//...
Using of [mainContext setRetainsRegisteredObjects:YES] and objectWithID don't resolve this issue.
EXC_BAD_ACCESS (code=1)
EXC_BAD_ACCESS (code=13)
-[__NSCFType contextDidSave:]: unrecognized selector sent to instance 0x7fc5c505d940
An observer of NSManagedObjectContextDidSaveNotification illegally threw an exception.
Objects saved = {
inserted = "{(\n)}";
updated = "{(\n <SomeEntity: 0x7fc5c55b6220> (entity: SomeEntity; id: 0x7fc5c5052b20 ... )}"; }
and exception = -[__NSCFType contextDidSave:]: unrecognized selector sent to instance 0x7fc5c505d940 with userInfo = (null)
I use a separate managed object context and fetch my managed objects inside this NSOperation.
Maybe it is something related to Core Data bugs or ARC? Maybe ARC cleans some of objects, that must be saved?
Because, without ARC everything was fine, all worked. When I turned on ARC - EXC_BAD_ACCESS.
Does anyone know why it occurs?

Maybe ARC deallocates some object that receives NSManagedObjectContextDidSaveNotification and this causes the exception?
I had something similar, and fixed it by making sure to removeObserver: before the object gets deallocated.
Note that the CoreData exception actually hides the notification center exception, so you don't get to see it.

Related

EXC_BAD_ACCESS while [WKInterfaceTable setNumberOfRows:withRowType]

I wanna to update table from a background thread using this part of the code
__block typeof(self.tableB) self_tableB = self.tableB;
[lwc setBaseControllerCallback:^(int ndx) {
__block typeof(ndx) ndx_t = ndx;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self_tableB setNumberOfRows: 0 withRowType:TABLEELEMENT];
[self_tableB setNumberOfRows: ndx_t withRowType:TABLEELEMENT];
}];
}];
where
^(int ndx) {
//...
}
is a block called from background thread (NSThread) and lwc - is an instance of my custom background thread class.
To clear this method is called like with:
//code inside thread
if (handlerBase_inner) {
handlerBase_inner(ndx++);
}
So, at
[self_tableB setNumberOfRows: ndx_t withRowType:TABLEELEMENT];
I can see EXC_BAD_ACCESS. Why? What is the
I worry about self_tableB. I'm not sure that you want a strong reference to it, artificially keeping it alive might cause it to have a dangling pointer back to its delegate.
__block __weak typeof(self.tableB) self_tableB = self.tableB;
Adding a weak annotation might to the trick.

dispatch async with blocks exc_bad_access non ARC project

i have a non arc project. i'm trying to use dispatch_async to get data from server and save it in sqlite. the dispatch_async happens inside a method with callback. on calling the method the app crashes with exc bad access. here is how i've implemented the code.
- (void) HandleData:(const char*) receivedData WithSuccess:(void(^)(BOOL finishing))completed
{
dispatch_queue_t fetchQ = dispatch_queue_create("Refreshing", NULL);
dispatch_async(fetchQ, ^{
[self write_data_in_sqlite]// **<--crash happens here in the method which is called here**
}
dispatch_sync(dispatch_get_main_queue(), ^{
completed(YES);
});
});
dispatch_release(fetchQ);
}
and i call the method as follow:
HandleResponse *handleResponse = [[[HandleResponse alloc] init] autorelease];
[handleResponse HandleData:aData WithSuccess:^(BOOL finishing) {
if(finishing)
{
//update the UI here
}
}];
if i remove the dispatch_async then it doesnt crash, but my UI gets blocked while writing to the sqlite.
what am i doing wrong?
edit:
removing the block and using dipatch_async produces the same exc_bad_access crash.
edit 2:
i tried example answer given below, it still crashes.
i thought to copy it then autorelease it. it crashes still but nit that often. i'm gonna check for memory leak. i'll report.
HandleResponse *handleResponse = [[[HandleResponse alloc] init] autorelease];
[handleResponse HandleData:aData WithSuccess: [[^(BOOL finishing) {
if(finishing)
{
//update the UI here
}
} copy] autorelease];
edit 3:
the crash happens in strlen even the xml content is in xmlResopnse. but why this happen with dispatch and not without it
xmlDocPtr xml= xmlParseMemory(xmlResopnse, strlen(xmlResponse);
edit 4:
as in answer below suggested not to use c objects in dispatch async. so i converted xmlResponse from const char* to nsstring and it doesnt crash.
Everything you've shown seems to be okay in terms of blocks and memory management. It must be something else.
I notice that you're passing in a C string (the char pointer receivedData) that you're not using. If you're not showing us the real code, and you are actually using the receivedData variable in the block, then that could be a problem, because the block simply captures the char pointer, but does not manage the memory of the string behind the pointer (it is not an Objective-C object). Therefore, it is possible that the C string is only valid in the calling scope (before the asynchronous operation), and no longer valid when the asynchronous operation runs. Your statement that something is crashing at strlen supports the idea that there is something wrong with some C string. You should try using NSString objects instead, since as objects they are properly memory-managed by blocks.

<__NSCFSet: 0x74957b0> was mutated while being enumerated

I can't undarstand why my code is crashes:
<__NSCFSet: 0x74957b0> was mutated while being enumerated
Previously I read simular topics but their problem was that the code calls in different threads. My code always calls in Thread 1.
It crashes times to time.
Here is a code where it happens:
- (void)processReceivedResponse:(JTResponse *)aResponse {
NSParameterAssert(aResponse);
id <JTRequestDelegate> delegate = [self processResponseWithReceiver:aResponse];
if (delegate == nil) {
for (JTObserver *someObserver in observers) {
if (someObserver.requestType == aResponse.type &&
![someObserver.delegate isEqual:delegate]) {
[someObserver.delegate didReceiveResponse:aResponse];
}
}
}
}
The error you're getting is caused by something changing the "observers" set while you're looping through it.
It's hard to tell what that might be from just the snippet you posted. Is something in the delegate you're invoking on someObserver changing the "observers" set?
You could try simply copying the observers set and looping over the copy:
for (JTObserver *someObserver in [[observers copy] autorelease]) {
...
}
If you're using ARC (automatic reference counting), you don't need to use autorelease.

memory leak when using callback

I'm having an issue with memory management when dealing with callbacks and async code in objective c.
I cant seem to find a way to release the instance that the callback is set on.
For example:
MyClass *myArchive = [[MyClass alloc] init] ;
[myArchive callBack:^(RKObjectLoader* objectLoader, id object ) {
NSLog(#"success");
} fail:^(RKObjectLoader* objectLoader, NSError* error) {
NSLog(#"failed");
}];
[myArchive searchArchive:words:paging];
The problem being that I don't know when or how to release the instance *myArchive. Using Instruments within xcode to profile my code I always get a leak here. The function searchArchive performs an async request to a server using restkit. I wont reference the instance from within the callback as I heard this causes a retain cycle and I have done some reading about using __block and other c approaches to avoid retain cycles which is all fine but as it stands now with no actual code happening within the callback how do I release the *myArchive instance. anyone able to explain how I should deal with this within objective-c?
EDIT:
This is where I set the callback in myclass
// Sets internal backs on this object which basically wrap the delegate
//
- (void)callBack: (void (^)(RKObjectLoader* objectLoader, id object))success
fail: (void (^)(RKObjectLoader* objectLoader, NSError* error))fail {
//sanity check
NSAssert(_currentDelegate != self, #"Delegate is another object. Can not set callback");
// store our callback blocks in the instance
_success = [success copy] ;
_fail = [fail copy] ;
}
and then release _success and _fail in dealloc
and within the #interface
#interface myClass : NSObject<RKObjectLoaderDelegate> {
// holds the block callback for "success"
void (^_success)(RKObjectLoader* objectLoader, id object);
// holds the block callback for "fail"
void (^_fail)(RKObjectLoader* objectLoader, NSError* error);
}
I hope this gives more insight into what I'm doing wrong.
EDIT 2:
Ok I'm beginning to see the errors now:
-(void)retrieveGallery{
//create call back for async and deal with the result
[_galleryItems callBack:^(RKObjectLoader* objectLoader, NSArray *objects) {
//success happy days. do a bunch of code here that does not cause leaks
} fail:^(RKObjectLoader* objectLoader, NSError* error) {
//retry the attempt to retrieve gallery data from the server
_retryCount++;
if (_retryCount < _maxRetryCount) {
[self retrieveGallery];
}
}];
//read the collection of gallery items from server
[_galleryItems readGallery];
}
The only actual memory leaks are when the callback catches a fail for what ever reason and then calls the [self retrieveGallery] function from within callback to attempt again. this is what is causing the leak so I'm guessing that is a big no no. How should I attempt the function (retrieveGallery in this case) again.
Memory management isn't really any different because you are using an asynchronous callback. myArchive should be a property of whatever class you are doing this in. You want it to stick around until the task is complete, right?
#property (retain) MyClass *myArchive;
Then..
myArchive = [[MyClass alloc] init];
void (^on_success_callback)(void) = ^(void){
NSLog(#"success");
self.myArchive = nil;
};
You need to make sure you are managing the callbacks properly, i.e. copying them from the stack and releasing them when you are done.
If you have retains and releases in your code you probably aren't using the accessor methods properly.

Error when deleting Core Data object: NSManagedObjectContext cannot delete objects in other contexts

I am encountering an issue when attempting to remove an object from my Core Data store. The error I receive when calling deleteOject is as follows: An NSManagedObjectContext cannot delete objects in other contexts.
I have found some documentation regarding this error online but it mostly relates to accessing the ManagedObjectContext in multiple threads which can cause issues, but I am not currently working on any other threads. I have gone through my code in an attempt to ensure that I am not creating any other context except for the one that I create in my AppDelegate and can not find a likely culprit.
The code that I am testing with is below:
NSMutableSet *remoteNids = [NSMutableSet setWithObjects:#"140", #"141", nil];
for (GCEvent *event in nodeEventsFromStore) {
if (![remoteNids containsObject:event]) {
NSLog(#"Event no longer exists on remote. Removing object %# from store.", event);
[[delegate managedObjectContext] deleteObject:event];
}
else {
NSLog(#"Event %# exists on remote", event);
}
}
It's highly unlikely that Core Data is lying to you. I would suggest putting an assert in your code like this:
NSAssert([delegate managedObjectContext] == [event managedObjectContext], #"Found two contexts: %# and %#", [delegate managedObjectContext, [event managedObjectContext]);
Run your app via Xcode with breakpoints on (so it breaks when you hit the assertion) and set MallocStackLoggingNoCompact=YES.
When the assert is triggered, you can use the gdb console like so:
(gdb) info malloc [address of event's MOC]
(gdb) info malloc [address of delegate MOC]
That will print the alloc stack trace and show you where you created the two moc's.
The simplest way to troubleshoot this would be to log the managed object context and then the managedObjectContext property of each GCEvent object before you delete it. If the error is correct the address of the two context will not match. If you don't have multiple context then the managedObjectContext property of each GCEvent is most likely nil.
You can get this error if you intialize a managed object directly i.e. using alloc-init, but then never assign it to the context by setting its managedObjectContext property to a context. A managed object context will treat any value other than itself as being another context even if that is a nil value.