I am using the following method to browse the photos library in iPhone:
enumerateGroupsWithTypes:usingBlock:failureBlock:
From the API doc and my test, I know the block runs asynchronously. However, my question is: how exactly this block runs asynchronously?
I.e. does it run via the same runloop as the main thread? or via a new & different runloop?
also, does it run in a new & different thread? (assuming 'thread' is not same as 'runloop')
Let's say that I want to do something to update the view(UI) inside the block, particularly do a :
[collectionView reloadData].
How will this "reloadData" message be handled? Will it be handled in the same runloop as the block itself? [Update question: will this "reloadData" be asynchronous or synchronous relative to this block's execution?]
And at last, in case I am asking dumb questions, can anyone suggest a book or other pointers to understand the inner working of asynchronous block in iOS program, e.g. how it's related to runloops and threads?
thanks.
the block is called on the main queue (running on the main thread)
no special runloop mode or so is entered ...
you can see it when you write a simple demo app
either the ALAssetFramework uses GCD dispatch or it registers as a source for runloop events.. but thats an implementation detail
about the update:
a block is a little like a regular function... so reloadData is synchronous normally and it will remain synchronous when used in a block therefore
Related
Lets say I have this
// a bunch of code...
FIRDatabase.database.reference.child("somechild").observeSingleEventOfType(.Value, withBlock{(snapshot) in
//some code inside of the completion handler})
Please don't read too much into the code snippet asking for more code, I only require a short answer. Where it says, "a bunch of code", assume that its actually some code that's on the MAIN queue. Now, when I write down the observeSingleEvent Firebase completion handler, my analysis on it is this.
observeSingleEvent fetches the snapshot on a background queue as to not block UI thats on the main queue.
Once it fetches the snapshot, the block of code after "in" is now back to the MAIN queue, so its fine to put any UI related code in there.
My whole app is based on this reasoning, so if I'm incorrect, please tell me what's actually going on.
That's indeed how the Firebase Database client works: all network and disk I/O happen off the main thread, then your callbacks/blocks are invoked on the main thread.
NSURLConnection.sendAsynchronousRequest
and
dispatch_async(dispatch_get_main_queue()) {}
I see that one is specific to urlRequests but could one have also used the dispatch_async function to get a data from URL then do UI related stuff in an asynchoronous fashion?
Thanks in advance,
Ace
Like you said the NSURLConnection method is specifically for sending async request and acts at a higher level of abstraction. Meaning a lot of heavy lifting is done for you under the hood.
Also what you do in the example is dispatching the call of the block you would supply asynchronously, but the block itself would be executed on the main queue, which would not be asynchronous.
You could for example download something in the background with the asynchronous request and then do UI related stuff on the main queue with your dispatch_async call.
So to speak: dispatch_async is part of the rather low-level GCD framework that can be used for a variety of things, like dispatching arbitrary codeblocks on different queues etc. See here for reference
I have a 'concurrent' NSOperation, and during it's work it uses some controller classes that internally use GCD. When these controller classes return with their completion block, the completion block is on another thread.
I know I could store the current thread in the operation start method and run performSelectorOnThread:, but ideally I would like to wrap the completion in a GCD block and dispatch onto the same thread as the operation started on. Is this even possible with GCD, as I can only specify a queue to dispatch to.
What's the best way to bring this work back onto the same thread that the operation started on? Apart from what I already suggested... unless this is the best way.
When the operation is completed the UI update or any other related things has to be done on main thread. The following link might be useful to you about CGD.
http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial
I don't think this is really possible/advisable. Since iOS 4 onwards, NSOperation is using GCD , and as GCD is managing my threads - I don't think I should be keeping references to them.
I did find some util methods for executing blocks of code on a particular thread. See Practical Blocks by Mike Ash or this article doing similar thing.
As my goal was to keep my core data calls on the same thread, instead I opted to upgrade my code to use parent/child managed object contexts with NSPrivateQueueConcurrencyType, and then used performBlock: on the managed object context to ensure all my call backs on the separate threads got executed correctly by core data.
I am doing a lot of GCD and asynchronous rendering and data retrieval work lately and I really need to nail the mental model about how asynchronous is done.
I want to focus on setNeedsDisplay and the NSURLConnectionDelegate suite of methods.
Is it correct to call setNeedsDisplay asynchronous? I often call it via dispatch_async(dispatch_get_main_queue(), ^{}) which confuses me.
The NSURLConnectionDelegate callbacks are described as asynchronous but are they not actually concurrently run on the main thread/runloop. I am a but fuzzy on the distinction here.
More generally in the modern iOS era of GCD what is the best practice for making GCD and these methods play nice together. I'm just looking for general guidelines here since I use them regularly and am just trying not to get myself in trouble.
Cheers,
Doug
No, you generally don't call setNeedsDisplay asynchronously. But if you're invoking this from a queue other than the main queue (which I would guess you are), then you should note that you never should do UI updates from background queues. You always run those from the main queue. So, this looks like the very typical pattern of dispatching a UI update from a background queue to the main queue.
NSURLConnection is described as asynchronous because when you invoke it, unless you used sendSynchronousRequest, your app immediately returns while the connection progresses. The fact that the delegate events are on the main queue is not incompatible with the notion that the connection, itself, is asynchronous. Personally, I would have thought it bad form if I can some delegate methods that were not being called from the same queue from which the process was initiated, unless that was fairly explicit via the interface.
To the question of your question's title, whether NSURLConnection uses GCD internally, versus another concurrency technology (NSOperationQueue, threads, etc.), that's an internal implementation issue that we, as application developers, don't generally worry about.
To your final, follow-up question regarding guidelines, I'd volunteer the general rule I alluded to above. Namely, all time consuming processes that would block your user interface should be dispatched to background queue, but any subsequent UI updates required by the background queue should be dispatched back to the main queue. That's the most general rule of thumb I can think of that encapsulates why we generally do concurrent programming and how to do so properly.
I'm trying to get my head around a asynchronicity; dispatch, multiple threads, run loops etc etc.
What's the difference between:
1) creating an NSURLRequest and NSURLConnection in a given method, and having it execute and us responding to the delegate methods (didReceiveResponse, didReceiveData, connectionDidFinishLoading, etc), and
2) creating a block and having it dispatch_async ?
With the first method it seems great that I have access to the delegate methods (do I still have access to those using dispatch?), and execution of the delegate methods are actioned when fired (or close to it?)
With the block/dispatch method, I'm guessing the block is processed synchronously within it's thread? And then comes back to the main thread to process the results? Example code I've been looking at:
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:
kLatestKivaLoansURL];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
So, the "self performSelector...." is performed AFTER the data is received? (what I meant before with synchronously - maybe the wrong term). And the next line of the block sends us back to the main thread.
What is the purpose of, or why is there a "waitUntilDone:YES"? Is it because if it's not there, other stuff could happen NOT in the main thread?
Is the first method above still only performed on the main thread?
and finally, what are the pros and cons of each in the case of a JSON query to a web page? Is there any great benefit of one method over the other?
1) When you use a NSURLConnection, either in your main thread or say in a NSOperation, you have full control of stopping it at any point, and tracking its progress. What you get back are delegate methods when various things happen, but you're not sitting and waiting for something to complete. If you want to stop it at anytime, you send it cancel, then you can release (or nil) it and forget about it.
2) So look at this. If you did this call in the main thread, it would wait until it succeeds or fails. Once started, it has to run to success or failure. This would block your UI if in the main thread. Put it in a block and run it on some other thread, and the same thing will happen - the chosen thread will block until the method ends. The use of 'self' to send the result will retain self. So if self is say a UIViewController, then even if you pop it (thinking its going to get removed), it stays around until this method completes, doing heaven knows what. This usage is very dangerous and may work often but fail catastrophically when a device has a crappy inet connection (for example).
The wait until does is to synchronize threads. If you want to know that the method has been run on the main thread, and only then proceed, use YES. If you just want the method queued and you're done (like in this case) you would just use NO.
The method will for sure be on the main thread - this Apple promises you with this method.
3) JSON
The majority of users I know use NSURLConnections from NSOperations or blocks. Operations can be cancelled (which would then cancel the connections) - so you can handle getting a 'Back' button press no matter how much is going on. If the query fails you can look at the html status (did you get a 400 or 500 error? a timeout? etc)
There is an open source project on github, hardly 200 lines of code, that provide an elegant and easy to use helper class to run operations (with demo code): /NSOperation-WebFetches-MadeEasy. I have personally used this code in over 8 apps still in the store with great success - a single OperationsRunner often has hundreds of fetches going on simultaneously, and the app has multiple classes running OperationsRunners at the same time.
If you process the JSON in the NSOperation, you will get real speedups on devices with multiple cores.