How to process the data of MKNetworkKit on a background thread? - objective-c

I am new with MKNetworkKit and I have a little design issue. I am trying to process the data fetched by the MKNetworkOperation on a background thread but I am not sure where to do that in order to keep the design clean.
[op onCompletion:^(MKNetworkOperation *completedOperation) {
NSDictionary *jsonDictionary = [completedOperation responseJSON];
// This part is always called on the main thread but
// I want to process here my jsonDictionary on a background thread
// to avoid blocking the main thread
} onError:^(NSError* error) {
errorBlock(error);
}];
The process time of my jsonDictionary takes a long time and I really don't want to do that on the main thread, how would you recommend me to switch to the background thread while keeping the design and philosophy of MKNetworkKit clean?
Thanks,
Martin

Within your completion handler use this code.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
//asynchronous code
dispatch_async(dispatch_get_main_queue(), ^{
//synchronous code
});
});

Related

ObjectiveC - Avoiding deadlock while synchronous dispatch to main queue from background

Recently I came to a point where I needed some block of code to execute always on the main thread synchronously. This block can be called from any thread. I solved this problem with the code that was already suggested in this SO answer by #Brad Larson
As the comments to this answer it is evident that the deadlock can occur, but I got into the deadlock very very easily. Please have a look at this code.
-(IBAction) buttonClicked
{
// Dispatch on the global concurrent queue async.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSString* data = [self getTheString];
NSLog(#"From Background Thread: %#", data);
};
// Dispatch on the main queue async.
dispatch_async(dispatch_get_main_queue(), ^{
NSString* data = [self getTheString];
NSLog(#"From Main Thread: %#", data);
};
}
// This method can be called from any thread so synchronize it.
// Also the code that sets the string variable based on some logic need to execute on main thread.
-(NSString*) getTheString
{
__block NSString* data = nil;
#synchronized(self)
{
// Have some code here that need to be synchronized between threads.
// .......
//
// Create a block to be executed on the main thread.
void (^blockToBeRunOnMainThread)(void) = ^{
// This is just a sample.
// Determining the actual string value can be more complex.
data = #"Tarun";
};
[self dispatchOnMainThreadSynchronously:blockToBeRunOnMainThread];
}
}
- (void) dispatchOnMainThreadSynchronously:(void(^)(void))block
{
if([NSThread isMainThread])
{
if (block)
{
block();
}
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
if (block)
{
block();
}
});
}
}
In this piece of code there are two simultaneous asynchronous requests to function getTheString (Assume you have no control over the buttonClicked method and how it calls getTheString api) . Suppose the request from global queue comes first and it is trying to run the block on the main thread synchronously, till that time background thread in waiting for main thread to execute the block synchronously, at the same time request from main queue comes and trying the acquire the lock from background thread, but as background thread in not complete main thread waiting for background thread to complete. Here we have a deadlock on main thread as main thread waiting for background thread to finish, and background thread is waiting for main thread to execute block.
If I remove the #synchronize statement everything works fine as expected. May be I don't need a #synchronize statement here but in same case you may need to have this. Or it can even happen from some other parts of the code.
I tried to search the whole net for the solution and also tried dispatch_semaphore but couldn't solve the issue. May be I am just not doing things the right way.
I assume this is classic problem of deadlock and faced by developers again and again, and probably have solved it to some extent. Can anyone help with this, or point me to right direction?
I would create a synchronous queue (NSOperationQueue would be simplest) and submit the block to be run on the main thread to that queue. The queue would dispatch the blocks in the order received, maintaining the ordering you desire. At the same time, it disassociates the synchronicity between calling the getTheString method and the dispatch to the main thread.

Waiting for asynchronous threads in objective-c

I am trying to wait for asynchronous threads in objective-c without blocking the UI thread (it is an app).
I have the following code:
-(void)MainUIThread
{
[exporter exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self exportDidFinish:exporter];
//wait here without blocking
});
}];
}
In C# I would use async and await, can I easily achieve this in objective-c?
[exporter exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
[self exportDidFinish:exporter]; // Its non blocking process
dispatch_async(dispatch_get_main_queue(), ^(void){
//Update your UI.
});
}];
Try above snippet.
You calling [self exportDidFinish:exporter] method on main thread that why it block your UI. I suppose exportDidFinish method have just a business logic then post that logic calculation in background thread using dispatch_get_global_queue then get it back on main thread using dispatch_get_main_queue().
What makes you think that you should wait for an asynchronous operation to finish? That's the whole point of asynchronous operation, you don't wait for it!
You called exportAsynchronouslyWithCompletionHandler and gave it a block. I don't know that method, but I assume it will do things asynchronously, and when it is finished it will call the block that you give it. The call to exportAsynchronouslyWithCompletionHandler will return very quickly, as soon as the method has set up its asynchronous operation.
That block dispatches another block calling "exportDidFinish:exporter" on the main thread, then it returns (with no reason to wait), then all the asynchronous code in exportAsynchronouslyWithCompletionHandler is finished.
All we have now is one block dispatched to the main queue. As soon as the run loop is idle, that block is executed on the main thread. The commented line that you added "// Wait here" is pointless. exportDidFinish:exporter will be called on the main thread when it's time to be called, and then we are done.

Replacing performSelectorInBackground with GCD

In my iOS app I'm running a computationally intensive task on a background thread like this:
// f is called on the main thread
- (void) f {
[self performSelectorInBackground:#selector(doCalcs) withObject:nil];
}
- (void) doCalcs {
int r = expensiveFunction();
[self performSelectorOnMainThread:#selector(displayResults:) withObject:#(r) waitUntilDone:NO];
}
How can I use GCD to run an expensive calculation such that it doesn't block the main thread?
I've looked at dispatch_async and some options for the GCD queue choice but I'm too new to GCD to feel like I understand it sufficiently.
You use dispatch_async like suggested.
For example:
// Create a Grand Central Dispatch (GCD) queue to process data in a background thread.
dispatch_queue_t myprocess_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
// Start the thread
dispatch_async(myprocess_queue, ^{
// place your calculation code here that you want run in the background thread.
// all the UI work is done in the main thread, so if you need to update the UI, you will need to create another dispatch_async, this time on the main queue.
dispatch_async(dispatch_get_main_queue(), ^{
// Any UI update code goes here like progress bars
}); // end of main queue code block
}); // end of your big process.
// finally close the dispatch queue
dispatch_release(myprocess_queue);
That's the general gist of it, hope that helps.

Wait until background selector is complete to call new method

I'm trying to perform the acquisition of data from the internet on the load of my view. To not lag the UI, I'm performing the HTML download and parsing by using
[self performSelectorInBackground:#selector(alertThreadMethod) withObject:nil];
which checks to see if there is an alert online. In order to display the information on the view however, iOS says that I need to use the main thread. So i call the display code right after:
[self performSelectorInBackground:#selector(alertThreadMethod) withObject:nil];
[self loadAlert];
In doing this, the [self loadAlert]; actually runs before the selector in the background (it is faster). Because of this, it does not have the information that the selector in the background is supposed to provide it.
How can I ensure that [self loadAlert]; runs after? Or is there a better way to do this?
You can either move loadAlert invocation into the alertThreadMethod or use Grand Central Dispatch serial queues, e.g.,
dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
dispatch_async(queue, ^{
[self alertThreadMethod];
[self loadAlert];
});
dispatch_release(queue);
Or, if loadAlert is updating the UI, since you do UI updates in the main queue, you'd do something like:
dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
dispatch_async(queue, ^{
[self alertThreadMethod];
dispatch_async(dispatch_get_main_queue(), ^{
[self loadAlert];
});
});
dispatch_release(queue);
By the way, if you're just doing this one task in background, rather than creating your own serial queue, you might just use one of the existing background queues. You only need to create a queue if you need the serial nature (i.e. you're going to be numerous dispatch_async calls and you can't have them running concurrently). But in this simple case, this might be even a little more efficient, bypassing the creating and releasing of the serial queue:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
[self alertThreadMethod];
dispatch_async(dispatch_get_main_queue(), ^{
[self loadAlert];
});
});
In your alertThreadMethod, after you have your information, call the method performSelectorOnMainThread:withObject:waitUntilDone: and pass it a selector to your loadAlert method.
-(void)alertThreadMethod
{
// get your information here
performSelectorOnMainThread:#selector(loadAlert) withObject:nil waitUntilDone:NO
}

Objective-C fast enumeration and asynchronous server operations. Model help?

If I have a method called "-uploadToServer:(Object *)objectToUpload", and a mutable array of several Objects, and I want to upload each object one after the other, how could I best handle this?
There are three important considerations:
Don't want NSOperation because I don't want to deal with threading issues
Need to wait for notification of task completion before continuing
Server calls are asynchronous and non-blocking
Here is some code I already have:
for (Object *task in objectsToUpload) {
[self uploadToServer:task];
//need to wait to get notification that upload completed
}
-(void)uploadToServer:(Object *)objectToUpload {
//perform asynchronous server operation here
//either block callback or delegate to notify
//self that upload finished
}
Seeing the above, how do you think I should handle this?
Don't want NSOperation because I don't want to deal with threading issues
Honestly, I think this is your easiest option. The only other way is to do asynchronous IO and use the run loop.
With NSOperation, you'd need two different kinds of operation called e.g. UploadOperation and NotifyOperation: one to upload an object and one to send a notification to the main thread when everything is done.
Then you'd loop through thwe objects putting them all on an NSOperationQueue in an UploadOperation, each one dependent on the previous one (addDependency:). Finally, you'd put the NotifyOperation on the queue dependent on the last UploadOperation.
The NotifyOperation overrides main as follows
-(void) main
{
[someObjectEgViewController performSelectorOnMainThread: #selector(finishedUpload)
withObject: nil
waitUntilDone: NO];
}
objectsToUpload is an NSMutableArray of tasks
-(void)uploadToServer{
//check if there is a task available
if (objectsToUpload.count > 0){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
//get first task
id nextTask = [objectsToUpload objectAtIndex:0];
//do something
//complete async
dispatch_async(dispatch_get_main_queue(), ^(void) {
//remove completed task
[objectsToUpload removeObject:nextTask];
//complete async upload task, check or notify and or start the next task
BOOL shouldDoNextTask = [self check];
if (shouldDoNextTask){
[self uploadToServer];
}
});
});
}
}
I would suggest you do not need to wait for the task to complete. What you need is to respond to the task's completion.
NSURLConnection will provide a delegate with callback methods.