iPhone - Grand Central Dispatch invalid mutable array - iphone

if I do this
NSMutableArray *allColors;
NSData *dataColor = [dictPLIST objectForKey:#"allColors"];
if (dataColor != nil) {
allColors = [NSMutableArray arrayWithArray:
[NSKeyedUnarchiver unarchiveObjectWithData:dataColor]];
}
dataColor = nil;
my allColors mutable array has valid contents, but if I create a GGC group and do this...
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
__block NSMutableArray *allColors;
dispatch_group_async(group, queue, ^{
NSData *dataColor = [dictPLIST objectForKey:#"allColors"];
if (dataColor != nil) {
allColors = [NSMutableArray arrayWithArray:
[NSKeyedUnarchiver unarchiveObjectWithData:dataColor]];
}
dataColor = nil;
});
// .... other stuff is added to the group
dispatch_group_notify(group, queue, ^{
dispatch_group_async(group, queue, ^{
// if I try to access allColors here, the app crashes
});
});
dispatch_release(group);
am I missing something?
thanks.

You are creating an autoreleased array and the autorelease pool is being drained by GCD sometime between when the first block executes and the second block executes.
Any time you are doing concurrent programming, whether by thread or using GCD, you must always hard retain any object that is to survive beyond one scope of execution.

Related

How to update a property of a ViewController from data retrieved asynchronously?

I would like to update a property of my ViewController self.matchedUsers, which takes data from a query that I run asynchronously through a block.
Then somewhere later When I retrieve the count via [self.matchedUsers count], I still get 0, despite knowing that multiple objects was added to my property. My question is, how do I ensure that my property gets updated even when I am retrieving data asynchronously through a block? Thanks!
Update:
For context, here is the block:
//Way earlier in an initializer:
self.matchedUsers = [[NSMutableArray alloc] init];
//In a method much later
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error){
//Code that updates self.matchedUsers with the NSArray objects
dispatch_async(dispatch_get_main_queue(), ^{
[self.matchedUsers addObjectsFromArray: objects];
});
//Question relates to ensure how property could be updated
}
}];
This should work provided you didn't forget to initialize matchedUsers, you check for its value after it's been changed and array does not lose its elements between the time you schedule and execute the block.
However, I would prefer to write a method that can be called from any thread, say
- (void)addUser ...
#synchronized(self.usersToAdd) {
[self.usersToAdd addObjectsFromArray: array];
Enqueue on main thread {
NSArray *addingNow;
#synchronized(self.usersToAdd) {
addingNow = [self.usersToAdd copy];
[self.usersToAdd removeObjects...
}
if (addingNow.count) {
[self.users addObjectsFromArray: addingNow;
[self.tableView insertRowsWithIndexPaths...
}
}
}
}
As others have written the problem could be missing initialization of matchedUsers but...
...the problem could also be due to your main thread being blocked. You write that you "somewhere later retrieve the count". If that is within the same method as the one that made the first dispatch you will be in trouble. Consider this code
NSMutableArray *collection = [[NSMutableArray alloc] init];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSArray *array = [[NSArray alloc] initWithObjects:#"1", nil];
dispatch_async(dispatch_get_main_queue(), ^{
for (NSString *item in array){
[collection addObject:item];
}
NSLog(#"A");
});
});
[NSThread sleepForTimeInterval:5];
NSLog(#"B");
If this is running on the main thread it will output first B on then A (no matter the sleep time), because the block is not run until the method finishes executing. If you on the other hand dispatch to another global queue instead of the main queue it will be A and then B.

Freezing the UI in IOS

The following code is freezing my UI. Cant do any actions.
- (void) longPoll {
//create an autorelease pool for the thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSError* error = nil;
NSURLResponse* response = nil;
NSURL* requestUrl = [NSURL URLWithString:#"myurl"];
NSURLRequest* request = [NSURLRequest requestWithURL:requestUrl];
//send the request (will block until a response comes back)
NSData* responseData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
[self dataReceived:responseData];
});
});
//compose the request
//pass the response on to the handler (can also check for errors here, if you want)
//clear the pool
}
- (void) startPoll {
//not covered in this example: stopping the poll or ensuring that only 1 poll is active at any given time
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) dataReceived: (NSData*) theData {
//process the response here
NSDictionary *dict=[theData JSONValue];
[self ParseJson:dict];
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
Can anyone give me the exact reason for it or any alternative to do the similar code for continues polling.
You are creating an infinite loop:
longCall calls dataReceived calls longCall etc....
What exactly you want to do. There is infinite loop between longPool and dataReceived
there should be mechanism where you stop this call and you can use
#autorelease {} block for create autorelease pool in ARC Enabled project and
NSAutoReleasePool class obj for Without ARC.

Why is my app not crashing when same managed object context is used in different threads?

I m trying to create a sample app with multi-threading and core data which is either suppose to crash or be in a deadlock.
I have created a concurrent queue and using a for loop call dispatch_async thrice.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *aMangedObjectContext = appDelegate.managedObjectContext;
for (int i = 0; i<=2; i++) {
LibXMLParser *parser = [[parserClass alloc] init];
parser.delegate = self;
dispatch_async(_queue, ^{
[parser startWithContext:aMangedObjectContext];
});
}
//I added another concurrent queue just to see if it crashes, but had no luck
for (int i = 0; i<=2; i++) {
LibXMLParser *parser = [[parserClass alloc] init];
parser.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
[parser startWithContext:aMangedObjectContext];
});
}
I create concurrent queue using this technique:
#property (nonatomic) dispatch_queue_t queue;
#property (nonatomic) dispatch_queue_t queue;
_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
_queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
I save data in main context:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *aMangedObjectContext = appDelegate.managedObjectContext;
NSError *error = nil;
if (![aManagedObjectContext save:&error]) {
NSLog(#"Error in adding a new bank %#, %#", error, [error userInfo]);
abort();
}
Here m using the same main context created in my app delegate in different threads.
And since this breaks the containment model in core data, (each thread should have its own private context) my app should not generate the proper output.
The app gets top 100 songs in each dispatch_async. so totally i get 300 songs.
I haven't registered my app to NSManagedObjectContextDidSaveNotification either, since i have used only the main context and not multiple.
each time save is called in different threads on the main context it self.
I just don't understand why my app is neither in deadlock nor is it crashing.
can any one tell me where i have gone wrong.
I just want my app to either crash or freeze when using same object context in multiple threads when i use one context in different.
Can someone tell me in what case a queue will access the same context simultaneously.Should i create another concurrent queue? I tried that and it did not work.
Thank you.

dispatch_group_wait with GCD

So I'm posting an array of images to my server. I want to use GCD to post the array asynchronously, but I also want to make the method in which this happens synchronous so that I can pass back a single response object. However the method dispatch_group_wait seems to be returning immediately (and not waiting for my blocks to finish). Is this an issue because I'm using a block within a block?
NSArray *keys = [images allKeys];
__block NSMutableDictionary *responses = [NSMutableDictionary dictionaryWithCapacity:[images count]];
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < [keys count]; i++) {
__block NSString *key = [keys objectAtIndex:i];
dispatch_group_async(group, queue, ^{
[self postImage:[images objectForKey:key] completionHandler:^(ServerResponse *response){
#synchronized(responses){
if ([response succeeded]) {
NSString *value = [[response data] objectForKey:#"image_token"];
[responses setObject:value forKey:key];
NSLog(#"inside success %#",responses);
} else {
NSString *error = response.displayableError;
if (!error) {
error = #"Sorry something went wrong, please try again later.";
}
[responses setObject:error forKey:#"error"];
[responses setObject:response forKey:#"response"];
}
}
}];
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
I want to simply wait for all of the [self postImage] methods to callback from the server and modify the responses dictionary.
Jonathan's semaphore example is on target. However, I mentioned using a condition variable as an alternative, so I thought I'd at least post an example. In general, a CV can be used to wait on more general conditions other than just N workers.
Note that condition variables have their place (though not necessarily here), usually best when a lock is already necessary to mutate shared state, then other threads can just wait for a specific condition.
NSUInteger numKeys = [keys count];
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:numKeys];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSUInteger i = 0; i < numKeys; i++) {
__block NSString *key = [keys objectAtIndex:i];
dispatch_async(queue, ^{
[self postImage:[images objectForKey:key] completionHandler:^(ServerResponse *response){
// Basically, nothing more than a obtaining a lock
// Use this as your synchronization primitive to serialize access
// to the condition variable and also can double as primitive to replace
// #synchronize -- if you feel that is still necessary
[conditionLock lock];
...;
// When unlocking, decrement the condition counter
[conditionLock unlockWithCondition:[conditionLock condition]-1];
}];
});
}
// This call will get the lock when the condition variable is equal to 0
[conditionLock lockWhenCondition:0];
// You have mutex access to the shared stuff... but you are the only one
// running, so can just immediately release...
[conditionLock unlock];
Without seeing the code for -postImage:completionHandler:, it's hard to say where things are getting scheduled, but I'm assuming they call through to something provided by iOS. If so, the handler blocks inside your block are dispatched to the global queue asynchronously, and then iOS-supplied function or method is returning immediately. As far as your dispatch group is concerned, the work is done almost instantly.
There's no easy way to get the group to wait for work that isn't already scheduled by the time to call to dispatch_group_wait() is made. However, we can add a lower-level thingamajigger called a semaphore that ensures our actions complete in the right order, and schedule it outside the scope of the inner (asynchronous) blocks.
NSUInteger numKeys = [keys count];
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSUInteger i = 0; i < numKeys; i++) {
__block NSString *key = [keys objectAtIndex:i];
dispatch_group_async(group, queue, ^{
// We create a semaphore for each block here. More on that in a moment.
// The initial count of the semaphore is 1, meaning that a signal must happen
// before a wait will return.
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
[self postImage:[images objectForKey:key] completionHandler:^(ServerResponse *response){
...
// This instructs one caller (i.e. the outer block) waiting on this semaphore to resume.
dispatch_semaphore_signal(sem);
}];
// This instructs the block to wait until signalled (i.e. at the end of the inner block.)
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
// Done with the semaphore. Nothing special here.
dispatch_release(sem);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// Now all the tasks should have completed.
dispatch_release(group);
There's a problem here though. Semaphores are a kernel resource. What if we have 100 tasks to perform, but the kernel can only supply 99 semaphores? Bad Thingsā„¢ happen. We can rebuild the code to use only one semaphore, though waiting for it will appear a bit wonky. Doing so actually obviates the dispatch group entirely, by the way, so we're essentially replacing the group with the semaphore. Let's watch!
NSUInteger numKeys = [keys count];
// set the count of the semaphore to the number of times it must be signalled before
// being exhausted. Up to `numKeys` waits will actually wait for signals this way.
// Additional waits will return immediately.
dispatch_semaphore_t sem = dispatch_semaphore_create(numKeys);
for (int i = 0; i < numKeys; i++) {
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSUInteger i = 0; i < numKeys; i++) {
__block NSString *key = [keys objectAtIndex:i];
dispatch_async(queue, ^{
[self postImage:[images objectForKey:key] completionHandler:^(ServerResponse *response){
...;
// This decrements the semaphore's count by one. The calling code will be
// woken up by this, and will then wait again until no blocks remain to wait for.
dispatch_semaphore_signal(sem);
}];
});
}
// At this point, all the work is running (or could have already completed, who knows?).
// We don't want this function to continue running until we know all of the blocks
// have run, so we wait on our semaphore a number of times equalling the number
// of signals we expect to get. If all the blocks have run to completion before we've
// waited for all of them, the additional waits will return immediately.
for (int i = 0; i < numKeys; i++) {
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
// Now all the tasks should have completed.
dispatch_release(sem);
Yes as has been stated, dispatch_group_wait() is not waiting because the postImage:completionHandler: call seems to be asynchronous. And if you REALLY need this block of code to execute synchronously then a semaphore or lock would seem to be an appropriate solution.
If, however you just want to collect all of the responses to one dictionary for processing, I believe that the most appropriate solution is to use GCD to it's full extent. And to use a dispatch queue to manage the mutable dictionary; This seems to be the solution preferred by apple in most of the documents I have seen.
The crux of the solution is to essentially transfer ownership of the mutable dictionary to a single queue and then only modify it from that queue. The 'ownership' I refer to is not object ownership in the memory management sense, but ownership in the right to modify sense.
I would consider doing something like this:
NSArray *keys = [images allKeys];
// We will not be reasigning the 'responses' pointer just sending messages to the NSMutableDictionary object __block is not needed.
NSMutableDictionary *responses = [NSMutableDictionary dictionaryWithCapacity:[images count]];
// Create a queue to handle messages to the responses dictionary since mutables are not thread safe.
// Consider this thread the owner of the dictionary.
dispatch_queue_t responsesCallbackQueue = dispatch_queue_create("com.mydomain.queue", DISPATCH_QUEUE_SERIAL);
for (NSString *key in keys) {
// This async call may not be needed since postImage:completionHandler: seems to be an async call itself.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self postImage:[images objectForKey:key] completionHandler:^(ServerResponse *response){
dispatch_async(responsesCallbackQueue, ^{
[responses setObject:response forKey:key];
// Perhaps log success for individual requests.
if (responses.count == keys.count){
NSLog(#"All requests have completed");
// All responses are available to you here.
// You can now either transfer back 'ownership' of the dictionary.
dispatch_async(dispatch_get_main_queue(), ^{
[self requestsHaveFinished:responses];
});
}
});
}];
});
}

IPhone: File Upload using dispatch_async for background upload

I want to perform a image upload while the running application at the background. I am able to upload the image to the server using the code on this link.
How can I upload a photo to a server with the iPhone?
I heard the NSUrlConnection can be asynchronous and it was used in the EPUploader. In my code, I add some extra method that will create a file in the application directory used for the EPUploader. During this creation of the file, I don't want it to create on the main thread of the application so I wrap all the code including the EPUploader itself with the
dispatch_async on the global queue. That way I won't block the main thread while the file are creating.
It has no problem if I use dispatch_sync but dispatch_async I find something weird when I placed the breakpoint at NSUrlConnection connection :
- (void)upload
{
NSData *data = [NSData dataWithContentsOfFile:filePath];
//ASSERT(data);
if (!data) {
[self uploadSucceeded:NO];
return;
}
if ([data length] == 0) {
// There's no data, treat this the same as no file.
[self uploadSucceeded:YES];
return;
} /* blah blah */
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
if (!connection) {
[self uploadSucceeded:NO];
return;
}
else
return;
I went to debug at the breakpoint and instead of going to if statement, the debugger jumps to the first return statement of this method. After that, the selectors I passed on to this class never gets called. This happen only on dispatch_async and it work on dispatch_sync on the global queue.
Does anybody know how to solve this issue?
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queue, ^{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
self.uploadIndex = 0;
ALAsset *asset = [self.assets objectAtIndex:0];
[[FileUploader alloc] initWithAsset:[NSURL URLWithString:#"http://192.168.0.3:4159/default.aspx"]
asset:asset
delegate:self
doneSelector:#selector(onUploadDone:)
errorSelector:#selector(onUploadError:)];
//[self singleUpload:self.uploadIndex];
[pool release];
});
There are a couple of things that should be changed.
Remove the NSAutoreleasePool, it is not needed.
Copy the block to the heap because it's life will probably exceed that of the calling code.
Example:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queue, [[^{
self.uploadIndex = 0;
ALAsset *asset = [self.assets objectAtIndex:0];
[[FileUploader alloc] initWithAsset:[NSURL URLWithString:#"http://192.168.0.3:4159/default.aspx"]
asset:asset
delegate:self
doneSelector:#selector(onUploadDone:)
errorSelector:#selector(onUploadError:)];
} copy] autorelease]);
If you are using ARC (which you certainly are since you should be) there is no need for the copy or autorelease.