GCD - executing methods on order after finishing others - iphone

I have a class that I call several times with different data.
That class, calls a web-service, parse it's response to NSDictionary, and save the data on Core Data.
The call of the web service and the saving in core data are done in different threads, using core data queues, so that the UI keeps responsive.
Class:
- (void)refreshDataFromWebService:(NSString *)webserviceWSDL
{
dispatch_queue_t receiveActivities = dispatch_queue_create("com.myApp.ws.wsdlMethod", NULL);
dispatch_async(receiveData, ^(void)
{
//call web service
//...
//parse received data to NSDictionary
//...
});
dispatch_release(receiveData);
}
//some work
//the class that works with the WS, calls a method on it's delegate, and the saveData is called.
- (void)saveData
{
dispatch_queue_t request_queue = dispatch_queue_create("com.myApp.insertDataOnCoreData", NULL);
dispatch_async(request_queue, ^{
//save data to CoreData with new Manage Object Context
//...
//...
});
dispatch_release(request_queue);
}
The issue is that I need to call this Class about 15 times, and in some order.
What is the best way to do it?
Should I call:
[SomeClass refreshDataFromWebService:method_1];
[SomeClass refreshDataFromWebService:method_2];
[SomeClass refreshDataFromWebService:method_3];
[SomeClass refreshDataFromWebService:method_4];
or should I do a different way?
The goal is that method_2 is only called after method_1 is finish saving on CoreData, due to relationships.
Thanks for you precious help,
Rui Lopes

Your first call to receive data and then save data the will not work in any scenario where it takes longer to receive data than it does to call save the data, which would likely almost always be the case. The save operation needs to be called inside of the receive block at the end. Now for the services to be called one at a time in order you should create an ivar for a serial dispatch queue for the class and use that and only release it in the dealloc method. Another option is to use NSOperations with a queue that has max concurrent operations set to 1.

Why don't you simply create a single serial queue for each instance of your class and then serialize the operations against the internal queue? This will ensure that method_2 happens after method_1 (assuming that method_1 was enqueue first, by design) while still allowing all instances of the class to run in parallel with respect to one another. This assumes, of course, that this is your goal - it's hard to tell from the code fragment in question.

Related

UI no response due to __psynch_mutexwait

My app sometimes becomes dead , and the call stack is like below,
Update:
I've spent two days but could not handle it yet.
What I have are contexts for each thread, and one retained context for a special serial queue.
What I am wondered about is that how the deadlock comes. Why all the threads are in waiting states? Just one possibility will be much appreciated.
Thanks a lot.
That happens some times when doing work in a notification handler that may result in other notifications being sent, easiest way to avoid it is to dispatch_async the work that needs to be done.
dispatch_async(dispatch_get_current_queue(), ^{
// The work that needs to be done...
});
This usually happens when one tries to access Core Data objects on a background thread using the main-threads context OR using the same managed object context on different threads (background or main) at the same time. For more details check out Core Data concurrency rules.
So to avoid both cases, the main rule is, each thread must have its own managed object context and initialize that context exactly where it's going to be used.
For example:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//
// Prepare your background core data context
//
if (self.privateContext == nil)
{
self.privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[self.privateContext setParentContext: - main managed object context - ];
[self.privateContext setUndoManager:nil]; // this context should not manage undo actions.
}
//
// Do any Core Data requests using this thread-save context
//
.
.
.
});

Freezes (not crashes) with GCD, blocks and Core Data

I have recently rewritten my Core Data driven database controller to use Grand Central Dispatch to manage fetching and importing in the background. Controller can operate on 2 NSManagedContext's:
NSManagedObjectContext *mainMoc instance variable for main thread. this contexts is used only by quick access for UI by main thread or by dipatch_get_main_queue() global queue.
NSManagedObjectContext *bgMoc for background tasks (importing and fetching data for NSFetchedresultsController for tables). This background tasks are fired ONLY by user defined queue: dispatch_queue_t bgQueue (instance variable in database controller object).
Fetching data for tables is done in background to not block user UI when bigger or more complicated predicates are performed.
Example fetching code for NSFetchedResultsController in my table view controllers:
-(void)fetchData{
dispatch_async([CDdb db].bgQueue, ^{
NSError *error = nil;
[[self.fetchedResultsController fetchRequest] setPredicate:self.predicate];
if (self.fetchedResultsController && ![self.fetchedResultsController performFetch:&error]) {
NSSLog(#"Unresolved error in fetchData %#", error);
}
if (!initial_fetch_attampted)initial_fetch_attampted = YES;
fetching = NO;
dispatch_async(dispatch_get_main_queue(), ^{
[self.table reloadData];
[self.table scrollRectToVisible:CGRectMake(0, 0, 100, 20) animated:YES];
});
});
} // end of fetchData function
bgMoc merges with mainMoc on save using NSManagedObjectContextDidSaveNotification:
- (void)bgMocDidSave:(NSNotification *)saveNotification {
// CDdb - bgMoc didsave - merging changes with main mainMoc
dispatch_async(dispatch_get_main_queue(), ^{
[self.mainMoc mergeChangesFromContextDidSaveNotification:saveNotification];
// Extra notification for some other, potentially interested clients
[[NSNotificationCenter defaultCenter] postNotificationName:DATABASE_SAVED_WITH_CHANGES object:saveNotification];
});
}
- (void)mainMocDidSave:(NSNotification *)saveNotification {
// CDdb - main mainMoc didSave - merging changes with bgMoc
dispatch_async(self.bgQueue, ^{
[self.bgMoc mergeChangesFromContextDidSaveNotification:saveNotification];
});
}
NSfetchedResultsController delegate has only one method implemented (for simplicity):
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
dispatch_async(dispatch_get_main_queue(), ^{
[self fetchData];
});
}
This way I am trying to follow Apple recommendation for Core Data: 1 NSManagedObjectContext per thread. I know this pattern is not completely clean for at last 2 reasons:
bgQueue not necessarily fires the same thread after suspension but since it is serial, it should not matter much (there is never 2 threads trying access bgMoc NSManagedObjectContext dedicated to it).
Sometimes table view data source methods will ask NSFetchedResultsController for info from bgMoc (since fetch is done on bgQueue) like sections count, fetched objects in section count, etc....
Event with this flaws this approach works pretty well of the 95% of application running time until ...
AND HERE GOES MY QUESTION:
Sometimes, very randomly application freezes but not crashes. It does not response on any touch and the only way to get it back to live is to restart it completely (switching back to and from background does not help).
No exception is thrown and nothing is printed to the console (I have Breakpoints set for all exception in Xcode).
I have tried to debug it using Instruments (time profiles especially) to see if there is something hard going on on main thread but nothing is showing up.
I am aware that GCD and Core Data are the main suspects here, but I have no idea how to track / debug this.
Let me point out, that this also happens when I dispatch all the tasks to the queues asynchronously only (using dispatch_async everywhere). This makes me think it is not just standard deadlock.
Is there any possibility or hints of how could I get more info what is going on? Some extra debug flags, Instruments magical tricks or build setting etc...
Any suggestions on what could be the cause are very much appreciated as well as (or) pointers to how to implement background fetching for NSFetchedResultsController and background importing in better way.
My first and very bad mistake was to fetch data for NSFetchedResultsController in the background queue.
It turned out after testing, I was way too sensitive about fetching times. I unnecessary did put fetchData execution to back thread making core data related code too complex when the longest fetch time I could generate took literally split of a second. This introduced way too much complexity and uncertainty for very small performance gain (if any).
I resigned form that by moving fetchData execution and all NSFetchedResultsControllerDelegate method to the main thread (simplified the code by removing GCD code).
When this was done I no longer needed mainMocDidSave: and unregistered from listening to the NSManagedObjectContextDidSaveNotification for main thread context.
I could also removed and unregistered DATABASE_SAVED_WITH_CHANGES notification posting.
This greatly simplified 'merging' mechanism as from this time on only background thread context merges its changes with main thread context (when saved). Let's call it one directional change notifications.
NSFetchedResultsControllerDelegate methods will be fired automatically as they pickup main thread context changes after merge.
Another important thing is to change dispatch_async to dispatch_sync in:
- (void)bgMocDidSave:(NSNotification *)saveNotification {
// CDdb - bgMoc didsave - merging changes with main mainMoc
// Previously was: dispatch_async
// dispatch_sync in this place may prevent from overlapping merging in some cases (many blocks in background queue)
dispatch_sync(dispatch_get_main_queue(), ^{
[self.mainMoc mergeChangesFromContextDidSaveNotification:saveNotification];
// !!! Extra notification NO needed anymore
});
}
Rule of thumb: SIMPLIFY and MINIMIZE amount of threads and NSManagedContexts.
I experienced that having 2 contexts is enough even for very big apps:
importContext operating in dedicated to GCD queue (MUST be serial queue). Just remember to save it at the end of the queue block's code.
mainConstext to operate on main UI thread (I call it READ context ;-) to be use when pulling data for the UI (presentation).
The DATABASE_SAVED_WITH_CHANGES notification looks a bit suspicious: Let's say bgMoc saves. Then bgMocDidSave: fires and merges the changes with the mainMoc which is fine. Then you fire a notification which in the end (I assume mainMocDidSave: fires when DATABASE_SAVED_WITH_CHANGES is raised) merges the changes back in bgMoc (which is where is originated from!). This does not sound like the right approach to me.
Also you might want to check in bgMocDidSave: that the notification originates from the bgMoc. If the mainMoc saves then changes are that bgMocDidSave: also fires.

Main thread's execution context

I need ideas on the following -
In the main thread at some point of execution say Point A(sequential logic), I need to remember the state of execution and delegate the execution of some other logic onto another thread, and let the main thread handle the UI events etc. When the delegated logic completes on the other thread then the flow of execution should continue from the point A and should recollect the entire execution context and proceed as if it never paused there.
Regards,
Sunil Phani Manne
It's hard to implement this exactly the way you're saying (for example do(things)... yield(other_thread); ...do(more_things);.
Here are a couple other options I can think of (you'd have to implement these yourself, using delegates or notifications for example; I'm just giving a basic outline of how it would work):
do(things)
[object doStuffOnOtherThreadWithCallback:^{ // block-based
do(more_things)...
}];
or...
do(things)
[object doStuffOnOtherThreadWithCallbackTarget:self // target/selector-based
selector:#selector(callbackSelector)];
}
- (void)callbackSelector {
do(more_things)...
}
One option you have is encapsulating the whole sequential logic that comes after Point A in your delegate and then execute it on the main thread when the secondary thread ends.
In other words, when you start the thread by calling, e.g.
[NSThread detachNewThreadSelector:sel toTarget:target withObject:delegate]
you can implement your target target so that it has a specific selector completion that is called at the end of sel on the main thread, like this (this is the your delegate class):
#implementation YOURDelegateClass {
.....
-(void)completion {
}
-(void)sel {
...
...
[self performSelectorOnMainThread:#selector(#"completion") withObject:self];
}
}
Of course you have many sub-options available here, like using a different call to start the background execution, etc.
The important point is that: you have to encapsulate in a selector all the logic that comes after Point A, and that you have to schedule the execution of this selector on the main thread, in order to get back to your context (although your context will have changed in the meantime because you will also have updated the UI).
EDIT:
Having to schedule the execution on the main thread defeats blocks from being suitable for this kind of callback. On the other side, block have the advantage that they in some limited sense give you access to the same lexical context in which the block was defined (which is roughly what you call context).
A workaround for this could be the following. Before detaching the new thread, store in a delegate the block you would like to execute at completion:
typedef void(^CustomBlock)(void);
#property (nonatomic, copy) CustomBlock customBlock;
....
int a = ...
delegate.customBlock = ^{
NSLog(#"hello %d.....", a);
}
[NSThread detachNewThreadSelector:sel...
....
-(void)completion {
[self customBlock];
}
Of course, you only get the context preservation that is guaranteed to you by block. But here you hit against a limit of the language.
If you need more context preservation, then the only possibility is encapsulating that context in your delegate class ivars.
One thing is for sure. There, most probably, isn't any direct feature in Cocoa that does that. Since you're saying that you can't duplicate the resources onto the new thread (for a very good reason), I am going to suggest that you make use of NSUndoManager. For every change you make in the thread, push an undo operation for that change onto the undo manager. At the end of the thread, execute all the undo operations in the undo manager object. This should, if done correctly, restore your state. Now, since the idea is untested, there could be a chance that not all actions can be undone. You will have to check that out first.

iOS Design: Using the delegate pattern in a library

I have a library project that uses ASIHTTPRequest to make URL requests and parse the responses. The library will be used by a separate iPhone app project.
If my iPhone controller code responds to a touch event, then calls into the library to make URL requests, how do I best perform the requests asynchronously?
In the library, if I use the delegate pattern for asynchronous requests as shown in the ASIHTTPRequest sample code, how do I return data from the library back to the calling code in the iPhone controller?
If I instead make synchronous URL requests with ASIHTTPRequest inside the library, what's the easiest way to put the calls to the library from the iPhone controller on a separate thread to avoid tying up the UI thread?
I'm no ASIHTTPRequest expert (NSURLRequest has always done me fine), but from a quick poke at the code, it looks like you'd use its delegate and didFinishSelector properties to give it someone to tell when the URL request is finished. So, for example:
- (void)startURLRequest
{
ASIHTTPRequest *myRequest;
/* code to set the request up with your target URL, etc here */
myRequest.delegate = self;
myRequest.didFinishSelector = #selector(HTTPRequestDidFinish:);
/* ... */
[myRequest startAsynchronous];
}
- (void)HTTPRequestDidFinish:(ASIHTTPRequest *)request
{
NSLog(#"Request %# did finish, got data: %#", request, request.data);
[myTargetForData didReceiveData:request.data fromURL:request.originalURL];
}
Apple explicitly recommend that you use the built-in runloop style mechanisms for asynchronous HTTP fetching, not separate threads. Using separate threads is likely to result in worse performance — at least in terms of battery life and/or device heat, even if it's still fast enough.
That said, as a learning point, by far the quickest way to switch something onto a separate thread and have it report back to the main thread (remember: UIKit objects may be messaged only from the main thread) is by changing this:
- (void)postResult:(NSString *)result
{
instanceOfUILabel.text = result;
}
- (void)doExpensiveOperationOn:(NSString *)source
{
/* lots of expensive processing here, and then... */
[self postResult:result];
}
- (IBAction)userWantsOperationDone:(id)sender
{
[self doExpensiveOperationOn:#"some value or another"];
}
Into this:
- (void)postResult:(NSString *)result
{
instanceOfUILabel.text = result;
}
- (void)doExpensiveOperationOn:(NSString *)source
{
/* we're on a thread without an autorelease pool now, probably we'll want one */
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* lots of expensive processing here, and then... */
/* in this simplified example, we assume that ownership of 'result' is here on this thread, possibly on the autorelease pool, so wait until postResult has definitely finished before doing anything that might release result */
[self performSelectorOnMainThread:#selector(postResult:) withObject:result waitUntilDone:YES];
[pool release];
}
- (IBAction)userWantsOperationDone:(id)sender
{
[self performSelectorOnBackgroundThread:#selector(doExpensiveOperationOn:) withObject:#"some value or another"];
}
There's about a million possible concurrency errors you can make by just going threaded without thinking about it though, and in that example an obvious problem is that whatever triggered the IBAction can [probably] trigger it several more times before doExpensiveOperationOn has finished. Multithreading is not something to be dashed into lightly.
For anyone's future reference, the easiest approach I found is to use the async request functionality built into ASIHTTPRequest, setting my library object as the delegate and setting the didFinishSelector: and didFailSelector: values to different methods inside my library for each request.
At the end of processing each response, I assign the parsed response (an NSString* or NSArray*) to a property of my library object instead of returning a value.
When my iOS view controller delegate is loaded, I add a change observer to each of the properties in the library using Key-Value Observing. When the response is parsed and assigned to the property in the library, the observeValueForKeyPath:ofObject:change:context: method is called in the code of my view controller delegate, and from there I can figure out which property was changed and therefore what UI needs to be updated.

Objective-C : Start an object on a background thread -- interact as usual?

I would like to have an object be callable from the main thread
MyObj* backgroundObject = [[MyObj alloc] initInBackground];
BOOL result = [backgroundObject computeResult];
But have all the methods of backgroundObject compute in another thread.
And also have backgroundObj be able to send messages to it's delegate. How can I do such a thing? Is it possible?
As others have pointed out, an NSObject doesn't exist on any one thread, a thread only comes into play when you start executing its methods.
My suggestion would be to not use manual threads for every time that a method is called on the object, but instead use NSOperations and an NSOperationQueue. Have an NSOperationQueue as an instance variable of the object, and have calls to the various methods on the object create NSOperations which are inserted into the queue. The NSOperationQueue will process these operations on a background thread, avoiding all of the manual thread management you would need to have for multiple accesses to methods.
If you make this NSOperationQueue have a maximum concurrency count of 1, you can also avoid locking shared resources within the object between the various operations that will be performed on a background thread (of course you'll still need to lock instance variables that can be accessed from the outside world).
For callbacks to delegates or other objects, I'd recommend using -performSelectorOnMainThread:withObject:waitUntilDone so that you don't have to think about making those delegate methods threadsafe.
See the Concurrency Programming Guide for more.
Sure, you can use NSThread for that, and have backgroundObject use performSelectorOnMainThread: to contact the delegate.
NSThread documentation
performSelectorOnMainThread:withObject:waitUntilDone:
Objects do not exist in threads AFAIK. The function you send to an object will always be performed on the thread you sent it from (unless you use NSThread or performSelectorOnMainThread or something along those lines).
What you need is a NSOperation and a block/delegate parameter to notify the caller of completion.
Look at the documentation of NSOperation and NSOperationQueues
You should use GCD:
/*
* I didn't initalised your object in background, because
* because in the most cases you need your object to stick around
* and only perfom the time consimung calculations in background
*/
MyObj* backgroundObject = [[MyObj alloc] initInBackground];
...
- (void)startBackgroundTask {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//in a perfectly async non blocking block :-)
BOOL result = [backgroundObject computeResult];
dispatch_async(dispatch_get_main_queue(), ^{
//post your result, or do something else with your result
[[NSNotificationCenter defaultCenter] postNotificationName:"backgroundComputeResultDone" object:[NSNumber numberWithBool:result]];
if (result) {
//do some stuff
}
});
});
}
Maybe you can take a look at these two videos from apple here:
WWDC 2011 - Session 210 - Mastering Grand Central Dispatch
WWDC 2011 - Session 308 - Blocks and Grand Central Dispatch in Practice