dispatch async with blocks exc_bad_access non ARC project - objective-c

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.

Related

GCD Prevents Call-back Blocks Being Called?

I am very new to GCD, but I am trying to only call certain code after other actions have completed. Anyway, this means I am using code you see below:
dispatch_group_async(group, queue, ^{
[self getTitlesArrayForChannel:channelID completionHandler:^(NSMutableArray *results) {
//Nothing in this block called, when method inside dispatch_group
[resultsDict setObject:results forKey:kFeedElementTitle];
NSLog(#"Received title result");
}];
});
So I am calling a method with a call-back block giving me the results of that method. When I put it inside the dispatch_group_asyncblock the call-back block doesn't ever get called. Why might this be?
Something else worth noting would be, I am getting a console message when running this:
Storing duplicate dispatch for GTLQueryYouTube selector setPart:
I have no idea what it really means and can't find any relatable examples online. Possible it has something to do with it?
Basically, I am trying to call two different methods with call-back blocks, giving me results, then once I have results from both, I want to call a final block giving me a dictionary of each of the results. But I bumped into this problem.
This has more to do with Google API, the error is not caused by GCD. You probably called this method:
+ (void)setStoredDispatchForClass:(Class<GTLRuntimeCommon>)dispatchClass
selector:(SEL)sel
returnClass:(Class)returnClass
containedClass:(Class)containedClass
jsonKey:(NSString *)jsonKey;
This method stores the dispatch details for a class and selector. If you call two times this method passing the same class and selector, this code will be executed:
NSDictionary *selDict = (NSDictionary *)CFDictionaryGetValue(classDict, sel);
if (selDict == nil) {
selDict = [NSDictionary dictionaryWithObjectsAndKeys:
jsonKey, kJSONKey,
returnClass, kReturnClassKey, // can be nil (primitive types)
containedClass, kContainedClassKey, // may be nil
nil];
CFDictionarySetValue(classDict, sel, selDict);
} else {
// we already have a dictionary for this selector on this class, which is
// surprising
GTL_DEBUG_LOG(#"Storing duplicate dispatch for %# selector %#",
dispatchClass, NSStringFromSelector(sel));
}
}
In the else the error gets printed. You may see the code here:
http://google-api-objectivec-client.googlecode.com/svn/trunk/Source/Objects/GTLRuntimeCommon.m
The Google API does not appear to be thread safe. I was having similar problems, then I adjusted my code to ensure all API method calls occur on the main thread. Problem disappeared.

blocks and async callback, dealloc object - need to nil the block

There is a similar question here, which doesn't explain exactly what I want: Objective C Blocks as Async-callbacks & BAD ACCESS
I have a view controller, which calls a service with an async callback. The callback is done using a block, which references variables on the view controller to populate them.
It looks like so:
- (void) loadData {
__block MyViewController *me = self;
[self.service executeWithCompletion:^(NSArray *result, NSError *error) {
if (!error) {
me.data = result;
}
}];
}
However, if I dealloc the view controller, 'me' is then badly accessed by the callback.
What is the simplest way of making 'me' NULL? If i put it as an iVar, it then brings back the circular reference... i think?
I think I'm missing something obvious....
Thanks
Are you targeting iOS 5.0 or later (or Mac OS X 10.7 or later)? If so, you can use ARC and a __weak variable (instead of a __block one). This will automatically zero out when the referenced object is deallocated. Your code would look like
- (void)loadData {
__weak MyViewController *me = self;
[self.service executeWithCompletion:^(NSArray *result, NSError *error) {
if (!error) {
MyViewController *strongMe = me; // load __weak var into strong
if (strongMe) {
strongMe.data = result;
}
}
}];
}
If you need support for an older OS then you need to find a different solution. One solution is to just go ahead and let the block retain self. If the service is guaranteed to execute the completion block (and then release it), this will only produce a temporary cycle that will break automatically when the completion block is run. Alternatively if you have some way to cancel the service (in a way that guarantees the block cannot be called after the cancellation), you can stick with the __block and just be sure to cancel the service in your -dealloc. There's other alternatives too but they're more complicated.
I did a combination of things above from the suggestions. Including nilling the blocks. Although, my objects are still not getting released immediately. i.e. I'd put a breakpoint on dealloc of MyViewController, and without the __block variable it would get called at a much later point in time (probably due to the async connection) and sometimes not at all.
The code is fairly complex - so I imagine there are other things going on for it to not work as suggested above.
What I have also done, is used Mike Ash's MAZeroingWeakRef, which i guess is the same as using __weak - which #KevinBallard suggested.
Below is how I've implemented it, and it appears to be working. Dealloc is called immediately on disposal of the view controller, which i want. And I can't get it to crash... and with the log comment that i've put in, I can already see that I'm dodging bullets.
- (void) loadData {
__block MAZeroingWeakRef *zeroWeakRef = [[MAZeroingWeakRef alloc] initWithTarget:self];
[zeroWeakRef setCleanupBlock: ^(id target) {
[zeroWeakRef autorelease];
}];
[self.service executeWithCompletion:^(NSArray *result, NSError *error) {
MyViewController *me = [zeroWeakRef target];
if (!me) {
DULog(#"dodged a bullet");
}
if (!error) {
me.data = result;
}
}];
}
Is there a real retain cycle problem that you're trying to avoid? Is there a reason that self should not simply be retained until -executeWithCompletion: completes? Is there any real chance that it won't complete?
So long as it really will eventually complete (even with failure) and so long as it releases the block after invoking it (perhaps by setting a property to nil), then the retain cycle will eventually be broken and all will be well.

App stops inconsistently at a call to dispatch_sync() [duplicate]

Im using XMPPFramework and in it's code there's a method like this:
- (NSDictionary *)occupants
{
if (dispatch_get_current_queue() == moduleQueue)
{
return occupants;
}
else
{
__block NSDictionary *result;
dispatch_sync(moduleQueue, ^{//IT BLOCKS HERE, WITHOUT MESSAGE
result = [occupants copy];
});
return [result autorelease];
}
}
[EDIT]
It blocks inconsistently, not always, since the app is not doing anything I pause it and I see the thread has stopped there, and it never continues to execute.
What is wrong? Any ideas?
Thanks
The behavior you explain perfectly matches with the one that appears when you try to send perform an operation on main thread via GCD while being on the main thread. So you should check if moduleQueue is the main queue, then this is it. Try checking if it is the main queue if it is, skip the dispatch_sync block.
Blocks sometimes need to retain variables to ensure they are available when they execute. If you use a local variable inside a block, you should initialise it to zero where you declare it outside the block.

App blocks while dipatching a queue

Im using XMPPFramework and in it's code there's a method like this:
- (NSDictionary *)occupants
{
if (dispatch_get_current_queue() == moduleQueue)
{
return occupants;
}
else
{
__block NSDictionary *result;
dispatch_sync(moduleQueue, ^{//IT BLOCKS HERE, WITHOUT MESSAGE
result = [occupants copy];
});
return [result autorelease];
}
}
[EDIT]
It blocks inconsistently, not always, since the app is not doing anything I pause it and I see the thread has stopped there, and it never continues to execute.
What is wrong? Any ideas?
Thanks
The behavior you explain perfectly matches with the one that appears when you try to send perform an operation on main thread via GCD while being on the main thread. So you should check if moduleQueue is the main queue, then this is it. Try checking if it is the main queue if it is, skip the dispatch_sync block.
Blocks sometimes need to retain variables to ensure they are available when they execute. If you use a local variable inside a block, you should initialise it to zero where you declare it outside the block.

ObjC delegate methods never gets called

I am creating instances of a class FlickrImage parsing a Flickr API photos response. The class has a method getLocation that does another API call to get the geolocation:
NSLog(#"getting location for %i",self.ID);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OFFlickrAPIRequest *flickrAPIRequest = [[OFFlickrAPIRequest alloc] initWithAPIContext[appDelegate sharedDelegate].flickrAPIContext];
[flickrAPIRequest setDelegate:self];
NSString *flickrAPIMethodToCall = #"flickr.photos.geo.getLocation";
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,#"api_key",self.ID,#"photo_id",nil];
[flickrAPIRequest callAPIMethodWithGET:flickrAPIMethodToCall arguments:requestArguments];
[pool release];
I have implemented the callback method that would catch the response from the API and update the FlickrImage instance with the geolocation data - but it never gets called. Here's where the instances get created:
NSDictionary *photosDictionary = [inResponseDictionary valueForKeyPath:#"photos.photo"];
NSDictionary *photoDictionary;
FlickrImage *flickrImage;
for (photoDictionary in photosDictionary) {
flickrImage = [[FlickrImage alloc] init];
flickrImage.thumbnailURL = [[appDelegate sharedDelegate].flickrAPIContext photoSourceURLFromDictionary:photoDictionary size:OFFlickrThumbnailSize];
flickrImage.hasLocation = TRUE; // TODO this is actually to be determined...
flickrImage.ID = [NSString stringWithFormat:#"%#",[photoDictionary valueForKeyPath:#"id"]];
flickrImage.owner = [photoDictionary valueForKeyPath:#"owner"];
flickrImage.title = [photoDictionary valueForKeyPath:#"title"];
[self.flickrImages addObject:[flickrImage retain]];
[flickrImage release];
[photoDictionary release];
}
The retain is there because I thought it might help solve this but it doesn't - and doesn't the NSMutableArray (flickrImages is a NSMutableArray) retain its members anyway?
EDIT I should add that the getLocation method (first code snippet) is launched in a thread:
[NSThread detachNewThreadSelector:#selector(getLocation) toTarget:self withObject:nil];
Your delegate method is never being called because the request is never being made. When you call callAPIMethodWithGET:, it sets up communications to run asynchronously on the current thread's run loop, then returns immediately. That way you can safely call it on the main thread without blocking.
Because you are calling the method from a thread you created yourself, it does not see the main run loop, but the run loop for your new thread. However, because you never execute the run loop, the messages are never sent, a response is never received, and your delegate is never called.
You could fix this by calling [[NSRunLoop currentRunLoop] run] in your new thread. That will let the work happen. But in this case would be easier to never detach a new thread in the first place. Your program won't block, and you won't have to worry about your delegate method needing to be reentrant.
I've also run into this problem when requesting and parsing XML on a different thread my solution was to do this:
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:start] && !isFinished){
}
Where start = [NSDate dateWithTimeIntervalSinceNow:3]; this is basically a timeout so that it doesn't live forever and isFinished is set to true when my parsing has completed.
I'm not familiar with these flicker API wrappers, but in this code:
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,#"api_key",self.ID,#"photo_id",nil];
Are you certain that both FLICKR_API_KEY, and self.ID are not nil? If either of them is nil, you'll end up with a dictionary that has less items in it than you intend.
Could you post the callback method(s) you have implemented – this could be just down to a simple typo, as it appears OFFlickrAPIRequest won’t do anything if the delegate does not implement the required callback.
Did you also implement flickrAPIRequest:didFailWithError: to see if there was an error returned from the API call?
Okay, I did solve it, with help from some of the suggestions above.
I did remove the extra retain because it did in fact create a memory leak. It did not look right from the outset, so my gut feeling about that is worth something, which is a good thing ;)
I removed the redundant threading because the API call is already asynchronous and does not require an additional thread to be non-blocking. After that, the callback method was being called but I ran into different problems concerning object retention. If interested you might want to check out that question, too
Thanks all.
The setDelegate method of OFFlickrAPIRequest does not retain the delegate like it should. This means you're stuck ensuring that your delegate is alive as long as the request is (or patching the class to properly own its own references).