How many types of calling NSOperationqueue? - ios

What are the differences among following types calling Queues,which one is the best?
A)
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
B)
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
[myQueue addOperationWithBlock:^{
// Background work
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Main thread work (UI usually)
}];
}];
C)Adding NSoperation which has subclassed to NSoperationQueue for example http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/
D)
[[NSOperation mainQueue] addOperation:myOperation];
IS it right approach? because this code adds NSoperation to mainQueue.This is not good for
background task.Usually mainQueue will be used for updating UI Only.
E)If I have missed anything except above call methods for Queue , please mention them also in answer.

None of those examples is best, and they're not even very different from each other. As the name implies, NSOperationQueue is a queue, i.e. a first in first out (FIFO) data structure, that contains operations. You can create your own operation queues, or you can use an existing one.
Example A is a reasonable example of using an existing queue, the main queue. You wouldn't want to put a synchronous network request on the main thread (which is what you get with +mainQueue) because it would block the user interface, but it's not necessarily a bad choice here because the request is asynchronous and the operation queue being passed in is used only to run the completion handler. Indeed, the completion handler might need to manipulate the user interface, and that should be done from the main queue.
Example B illustrates creating a new operation queue and scheduling an operation on that queue. That operation in turn schedules another operation on the main queue. This is a pretty typical scenario -- again, you should only manipulate the UI from the main thread, so it's common to have a background operation create an operation that runs on the main thread in order to update the UI.
Example C is similar to B, except that the operation in question is a subclass rather than one created from a block. NSOperation existed before Grand Central Dispatch and blocks came along, and it used to be that the only way to create an operation that did something interesting was to subclass NSOperation and override -main. The blog post you linked says it was posted Feb. 16, 2008, which would certainly have been from that era. Creating operations from blocks is a newer and often more concise style, but there's nothing wrong with subclassing especially if you might need to perform the same kind of operation in several places. Note also that that article uses -performSelectorOnMainThread:withObject:waitUntilDone:, which is an easier way to run something on the main thread than creating another NSOperation subclass.
Example D is too vague to really comment on -- it merely shows how to add some unspecified operation to the main queue. You're right that you wouldn't want to do that for long-running operations -- those should be scheduled on a background queue instead to avoid blocking the UI. But without knowing what myOperation does, you can't say that it's right or wrong.
So, none of your examples are incorrect, and none is really better than another. To the extent that they're different, it's because they're used in different situations. For example, NSURLConnection takes an NSOperationQueue and a block as parameters because it needs to wait until the connection is done before it schedules an operation created from the completion block. Once the connection is done, though, NSURLConnection will do pretty much what you see in examples B and D.

Related

Concurrent vs Serial Queue for executing large number of Server requests in iOS

If an iOS app has to make hundreds of server requests in background and save the result in local mobile database, which approach would be better in terms of performance (less crashes)?
Passing all requests as 1 block in Global Background Queue
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
for (i=0;i<users;i++)
{
Call Api 1
Call Api 2
Call Api 3
}
});
OR
Creating 'n' number of User Serial Queues and adding all 3 api calls as individual blocks in each serial queue.
for (i=0;i<users;i++)
{
dispatch_queue_t myQueue = dispatch_queue_create([[users objectAtIndex:i] UTF8String], DISPATCH_QUEUE_SERIAL);
dispatch_async(myQueue, ^{
Call Api 1
});
dispatch_async(myQueue, ^{
Call Api 2
});
dispatch_async(myQueue, ^{
Call Api 3
});
}
Edit: In each Call Api, I am using NSOperationQueue.
queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {..}
I would suggest using NSOperations rather. Create 'n' NSOperations one for each API. Create a NSOperatioQueue, add the NSOperations to queue and sit back and relax while iOS takes the burden of deciding how many operations to run concurrently and all other complicated task ascociated with thread and memory for you :)
The major difference between GCD and NSOperations is the ability to pause and resume the operations :) In case of GCD once submitted operation is bound to happen and there is no way you can skip them or pause them :)
Adding the dependencies between multiple operations in GCD is cumbersome where as adding dependencies and prioritising tasks in NSOperations is just a matter of few statements :)
EDIT
As per your edit you are already using NSOperation for each API. So there is absolutely no need to call the NSOperations in dispatch_async again :) Rather consider creating an NSOperationQueue and adding these NSOperations to queue :)
QA for your comments
1.What if I create new NSOperationQueue every time instead of adding NSOperations to single NSOperationQueue?
Creating a seperate queue for each NSOperation is never a great idea :)
NSOperationQueue was suggested only with the intention of reducing the complication you will have to bear with multiple threads manually :)
When you submit an NSOperation to NSOperationQueue you can specify how many concurrent operations can be performed by NSOperationQueue.
Notice that it is just an upper value :) If you specify maximum concurrent operation allowed to 10 it means when iOS has resources like memory and CPU cycles it may carry out 10 operations.
You being a developer may not be always in a great position to decide what is the optimal number of threads that system can afford :) but OS can always do it efficiently. So it is always advisable to transfer these burden on OS as much as possible :)
But if you want to have a separate thread for each API calls rather then creating a separate queue you can consider executing the NSOpertaions individually by calling [NSOperation start] Creating an NSOperationQueue for each NSOperation is overhead.
I believe if you have any experience with JAVA you must have came across ExecutorPool concept. NSOperationQueue does exactly what ExecutorPool does for JAVA :)
2.Should I use [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] .. instead of [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init]
I believe you are aware that all you UI operations are performed in main thread and main thread makes use of Main Queue to dispatch the events. Performing the lengthy operations on Main Queue and keeping it busy will lead to a very bad user experience.
Calling 100 API's on Main queue may lead to user uninstalling your app and giving the worst possible rating :)
I guess you now know the answer for your question now :) to be specific use [[NSOperationQueue alloc] init] for your situation.
First you should read this: GCD Practicum.
Second you shouldn't roll your own solution here. Instead use AFNetworking, and just make the requests as needed. It has its own operation queue already setup so you don't need to deal with that. Then set the maximum number of concurrent requests to some value that you tune by hand. Start with four.

Perform synchronous operations

Say I want to implement a pattern like so:
a = some array I download from the internet
b = manipulate a somehow (long operation)
c = first object of b
These would obviously need to be called synchronously, which is causing my problems in Objective C. I've read about NSOperationQueue and GCD, and I don't quite understand them, or which would be appropriate here. Can someone please suggest a solution? I know I can also use performSelector:#selector(sel)WaitUntilDone, but that doesn't seem efficient for larger operations.
So create a serial dispatch queue, dump all the work there (each in a block), and for the last block post a method back to yourself on the main queue, telling your control class that the work is done.
This is by far and away the best architecture for much such tasks.
I'm glad your question is answered. A couple of additional observations:
A minor refinement in your terminology, but I'm presuming you want to run these tasks asynchronously (i.e. don't block the main queue and freeze the user interface), but you want these to operate in a serial manner (i.e., where each will wait for the prior step to complete before starting the next task).
The easiest approach, before I dive into serial queues, is to just do these three in a single dispatched task:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doDownloadSynchronously];
[self manipulateResultOfDownload];
[self doSomethingWithFirstObject];
});
As you can see, since this is all a single task running these three steps after each other, you can really dispatch this to any background queue (in the above, it's to one of the global background queues), but because you're doing it all within a given dispatched block, these three steps will sequentially, one after the next.
Note, while it's generally inadvisable to create synchronous network requests, as long as you're doing this on a background queue, it's less problematic (though you might want to create an operation-based network request as discussed below in point #5 if you want to enjoy the ability to cancel an in-progress network request).
If you really need to dispatch these three tasks separately, then just create your own private serial queue. By default, when you create your own custom dispatch queue, it is a serial queue, e.g.:
dispatch_queue_t queue = dispatch_queue_create("com.company.app.queuename", 0);
You can then schedule these three tasks:
dispatch_async(queue, ^{
[self doDownloadSynchronously];
});
dispatch_async(queue, ^{
[self manipulateResultOfDownload];
});
dispatch_async(queue, ^{
[self doSomethingWithFirstObject];
});
The operation queue approach is just as easy, but by default, operation queues are concurrent, so if we want it to be a serial queue, we have to specify that there are no concurrent operations (i.e. the max concurrent operation count is 1):
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
[queue addOperationWithBlock:^{
[self doDownloadSynchronously];
}];
[queue addOperationWithBlock:^{
[self manipulateResultOfDownload];
}];
[queue addOperationWithBlock:^{
[self doSomethingWithFirstObject];
}];
This begs the question of why you might use the operation queue approach over the GCD approach. The main reason is that if you need the ability to cancel operations (e.g. you might want to stop the operations if the user dismisses the view controller that initiated the asynchronous operation), operation queues offer the ability to cancel operations, whereas it's far more cumbersome to do so with GCD tasks.
The only tricky/subtle issue here, in my opinion, is how do you want to do that network operation synchronously. You can use NSURLConnection class method sendSynchronousRequest or just grabbing the NSData from the server using dataWithContentsOfURL. There are limitations to using these sorts of synchronous network requests (e.g., you can't cancel the request once it starts), so many of us would use an NSOperation based network request.
Doing that properly is probably beyond the scope of your question, so I might suggest that you might consider using AFNetworking to create an operation-based network request which you could integrate in solution #4 above, eliminating much of the programming needed if you did your own NSOperation-based network operation.
The main thing to remember is that when you're running this sort of code on a background queue, when you need to do UI updates (or update the model), these must take place back on the main queue, not the background queue. Thus if doing a GCD implementation, you'd do:
dispatch_async(queue, ^{
[self doSomethingWithFirstObject];
dispatch_async(dispatch_get_main_queue(),^{
// update your UI here
});
});
The equivalent NSOperationQueue rendition would be:
[queue addOperationWithBlock:^{
[self doSomethingWithFirstObject];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// update your UI here
}];
}];
The essential primer on these issues is the Concurrency Programming Guide.
There are a ton of great WWDC videos on the topic including WWDC 2012 videos Asynchronous Design Patterns with Blocks, GCD, and XPC and Building Concurrent User Interfaces on iOS and WWDC 2011 videos Blocks and Grand Central Dispatch in Practice and Mastering Grand Central Dispatch
I would take a look at reactive cocoa (https://github.com/ReactiveCocoa/ReactiveCocoa), which is a great way to chain operations together without blocking. You can read more about it here at NSHipster: http://nshipster.com/reactivecocoa/

Clarifications needed for concurrent operations, NSOperationQueue and async APIs

This is a two part question. Hope someone could reply with a complete answer.
NSOperations are powerful objects. They can be of two different types: non-concurrent or concurrent.
The first type runs synchronously. You can take advantage of a non-concurrent operations by adding them into a NSOperationQueue. The latter creates a thread(s) for you. The result consists in running that operation in a concurrent manner. The only caveat regards the lifecycle of such an operation. When its main method finishes, then it is removed form the queue. This is can be a problem when you deal with async APIs.
Now, what about concurrent operations? From Apple doc
If you want to implement a concurrent operation—that is, one that runs
asynchronously with respect to the calling thread—you must write
additional code to start the operation asynchronously. For example,
you might spawn a separate thread, call an asynchronous system
function, or do anything else to ensure that the start method starts
the task and returns immediately and, in all likelihood, before the
task is finished.
This is quite almost clear to me. They run asynchronously. But you must take the appropriate actions to ensure that they do.
What it is not clear to me is the following. Doc says:
Note: In OS X v10.6, operation queues ignore the value returned by
isConcurrent and always call the start method of your operation from a
separate thread.
What it really means? What happens if I add a concurrent operation in a NSOperationQueue?
Then, in this post Concurrent Operations, concurrent operations are used to download some HTTP content by means of NSURLConnection (in its async form). Operations are concurrent and included in a specific queue.
UrlDownloaderOperation * operation = [UrlDownloaderOperation urlDownloaderWithUrlString:url];
[_queue addOperation:operation];
Since NSURLConnection requires a loop to run, the author shunt the start method in the main thread (so I suppose adding the operation to the queue it has spawn a different one). In this manner, the main run loop can invoke the delegate included in the operation.
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:#selector(start) withObject:nil waitUntilDone:NO];
return;
}
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
NSURLRequest * request = [NSURLRequest requestWithURL:_url];
_connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (_connection == nil)
[self finish];
}
- (BOOL)isConcurrent
{
return YES;
}
// delegate method here...
My question is the following. Is this thread safe? The run loop listens for sources but invoked methods are called in a background thread. Am I wrong?
Edit
I've completed some tests on my own based on the code provided by Dave Dribin (see 1). I've noticed, as you wrote, that callbacks of NSURLConnection are called in the main thread.
Ok, but now I'm still very confusing. I'll try to explain my doubts.
Why including within a concurrent operation an async pattern where its callback are called in the main thread? Shunting the start method to the main thread it allows to execute callbacks in the main thread, and what about queues and operations? Where do I take advantage of threading mechanisms provided by GCD?
Hope this is clear.
This is kind of a long answer, but the short version is that what you're doing is totally fine and thread safe since you've forced the important part of the operation to run on the main thread.
Your first question was, "What happens if I add a concurrent operation in a NSOperationQueue?" As of iOS 4, NSOperationQueue uses GCD behind the scenes. When your operation reaches the top of the queue, it gets submitted to GCD, which manages a pool of private threads that grows and shrinks dynamically as needed. GCD assigns one of these threads to run the start method of your operation, and guarantees this thread will never be the main thread.
When the start method finishes in a concurrent operation, nothing special happens (which is the point). The queue will allow your operation to run forever until you set isFinished to YES and do the proper KVO willChange/didChange calls, regardless of the calling thread. Typically you'd make a method called finish to do that, which it looks like you have.
All this is fine and well, but there are some caveats involved if you need to observe or manipulate the thread on which your operation is running. The important thing to remember is this: don't mess with threads managed by GCD. You can't guarantee they'll live past the current frame of execution, and you definitely can't guarantee that subsequent delegate calls (i.e., from NSURLConnection) will occur on the same thread. In fact, they probably won't.
In your code sample, you've shunted start off to the main thread so you don't need to worry much about background threads (GCD or otherwise). When you create an NSURLConnection it gets scheduled on the current run loop, and all of its delegate methods will get called on that run loop's thread, meaning that starting the connection on the main thread guarantees its delegate callbacks also happen on the main thread. In this sense it's "thread safe" because almost nothing is actually happening on a background thread besides the start of the operation itself, which may actually be an advantage because GCD can immediately reclaim the thread and use it for something else.
Let's imagine what would happen if you didn't force start to run on the main thread and just used the thread given to you by GCD. A run loop can potentially hang forever if its thread disappears, such as when it gets reclaimed by GCD into its private pool. There's some techniques floating around for keeping the thread alive (such as adding an empty NSPort), but they don't apply to threads created by GCD, only to threads you create yourself and can guarantee the lifetime of.
The danger here is that under light load you actually can get away with running a run loop on a GCD thread and think everything is fine. Once you start running many parallel operations, especially if you need to cancel them midflight, you'll start to see operations that never complete and never deallocate, leaking memory. If you wanted to be completely safe, you'd need to create your own dedicated NSThread and keep the run loop going forever.
In the real world, it's much easier to do what you're doing and just run the connection on the main thread. Managing the connection consumes very little CPU and in most cases won't interfere with your UI, so there's very little to gain by running the connection completely in the background. The main thread's run loop is always running and you don't need to mess with it.
It is possible, however, to run an NSURLConnection connection entirely in the background using the dedicated thread method described above. For an example, check out JXHTTP, in particular the classes JXOperation and JXURLConnectionOperation

Recommended Design Patterns for Asynchronous Blocks?

I am working on an iOS app that has a highly asynchronous design. There are circumstances where a single, conceptual "operation" may queue many child blocks that will be both executed asynchronously and receive their responses (calls to remote server) asynchronously. Any one of these child blocks could finish execution in an error state. Should an error occur in any child block, any other child blocks should be cancelled, the error state should be percolated up to the parent, and the parent's error-handling block should be executed.
I am wondering what design patterns and other tips that might be recommended for working within an environment like this?
I am aware of GCD's dispatch_group_async and dispatch_group_wait capabilities. It may be a flaw in this app's design, but I have not had good luck with dispatch_group_async because the group does not seem to be "sticky" to child blocks.
Thanks in advance!
There is a WWDC video (2012) that will probably help you out. It uses a custom NSOperationQueue and places the asynchronous blocks inside NSOperationsso you can keep a handle on the blocks and cancel remaining queued blocks.
An idea would be to have the error handling of the child blocks to call a method on the main thread in the class that handles the NSOperationQueue. The class could then cancel the rest appropriately. This way the child block only need to know about their own thread and the main thread. Here is a link to the video
https://developer.apple.com/videos/wwdc/2012/
The video is called "Building Concurrent User Interfaces on iOS". The relevant part is mainly in the second half, but you'll probably want to watch the whole thing as it puts it in context nicely.
EDIT:
If possible, I'd recommend handling the response in an embedded block, which wraps it nicely together, which is what I think you're after..
//Define an NSBlockOperation, and get weak reference to it
NSBlockOperation *blockOp = [[NSBlockOperation alloc]init];
__weak NSBlockOperation *weakBlockOp = blockOp;
//Define the block and add to the NSOperationQueue, when the view controller is popped
//we can call -[NSOperationQueue cancelAllOperations] which will cancel all pending threaded ops
[blockOp addExecutionBlock: ^{
//Once a block is executing, will need to put manual checks to see if cancel flag has been set otherwise
//the operation will not be cancelled. The check is rather pointless in this example, but if the
//block contained multiple lines of long running code it would make sense to do this at safe points
if (![weakBlockOp isCancelled]) {
//substitute code in here, possibly use *synchronous* NSURLConnection to get
//what you need. This code will block the thread until the server response
//completes. Hence not executing the following block and keeping it on the
//queue.
__block NSData *temp;
response = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
[operationQueue addOperationWithBlock:^{
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
//Call selector on main thread to handle canceling
//Main thread can then use handle on NSOperationQueue
//to cancel the rest of the blocks
});
else {
//Continue executing relevant code....
}
}];
}
}];
[operationQueue addOperation:blockOp];
One pattern that I have come across since posting this question was using a semaphore to change what would be an asynchronous operation into a synchronous operation. This has been pretty useful. This blog post covers the concept in greater detail.
http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch-semaphore
There are many ways to achieve async behavior in cocoa.
GCD, NSOperationQueue, performSelectorAfterDelay, creating your own threads. There are appropriate times to use these mechanisms. Too long to discuss here, but something you mentioned in your post needs addressing.
Should an error occur in any child block, any other child blocks should be cancelled, the error state should be percolated up to the parent, and the parent's error-handling block should be executed.
Blocks cant throw errors up the stack. Period.

In GCD, is there a way to tell if the current queue is concurrent or not?

In GCD, is there a way to tell if the current queue is concurrent or not?
I'm current attempting to perform a delayed save on some managed object contexts but I need to make sure that the queue the code is currently executed on is thread-safe (in a synchronous queue).
If you actually have to determine whether or not the queue passed in to you is serial or concurrent, you've almost certainly designed things incorrectly. Typically, an API will hide an internal queue as an implementation detail (in your case, your shared object contexts) and then enqueue operations against its internal queue in order to achieve thread safety. When your API takes a block and a queue as parameters, however, then the assumption is that the passed-in block can be safely scheduled (async) against the passed-queue (when, say, an operation is complete) and the rest of the code is factored appropriately.
Yes, assuming you're doing the work in an NSOperation subclass:
[myOperation isConcurrent] //or self, if you're actually in the NSOperation
If you need to ensure some operations are always executed synchronously, you can create a specific operation queue and set its maximum concurrent operations to 1.
NSOperationQueue * synchronousQueue = [[NSOperationQueue alloc] init];
[synchronousQueue setMaxConcurrentOperationCount:1];
GCD takes some planning ahead. The only other way I can think of is to observe the value isExecuting (or similar) on your NSOperation objects. Check out this reference on that. This solution would be more involved, so I hope the other one works for you.

Resources