I am using dispatch_async and a block to retrieve server data every 3 seconds or so. What is the method of handling the view either disappearing or the user shutting the program down?
Would it be a boolean flag that the async block checks every now and then? If so, what if the view exits while the async block is sleeping?
You cannot easily cancel a dispatch call, so your best bet is to move to an NSOperation instead. There is a highly relevent video from WWDC 2012, Session 211 - Building Concurrent User Interfaces on iOS which covers precisely the kind of problem you describe. I definitely suggest you watch it.
The basic approach is to create an NSBlockOperation which can check the -isCancelled property on itself to return early if it gets cancelled. Then you can cancel the operation in viewDidDisappear.
An alternative approach would be to use NSTimer which can also be easily invalidated/cancelled. This might actually be the simplest solution for you given the description of what your code is doing.
Related
I'm implementing an iOS app which make requests using REST service. And I want to cancel all the previous REST calls when I make a new call. Can I do it in the global queue in GCD without Operation Queue? Thanks
GCD does not provide an API to cancel blocks. So you will have to implement this cancellation yourself.
The easiest way probably would be to set a global flag 'canceled' and check that inside of your blocks. If the flag is set, immediately return from your block. Then after all blocks have finished you can reset the flag and enqueue your new block.
Even though that sounds simple, this requires some nontrivial code. It would be much easier to use NSOperationQueue instead of reimplementing its features on top of plain GCD.
Is is possible in an iOS app to do the following:
Pause execution of a method running on the main thread.
Allow the main thread to continue, completing one loop of the main run loop (or continuing for a specified time period)
Resume execution of the previous paused method
?
I've searched and can't find anything that allows me to do this, but I have a feeling I've seen it done in the past by a programmer I previously worked with.
The motivation for this is the following:
I'm writing a test of a message routing class
The test (a) sends a message and then (b) analyses the outcome to determine if the test passed
The send message is sent using performSelectorOnMainThread:withObject:waitUntilDone:NO
There are 2 ways I can think to resolve this:
Split my test up and use performSelector:withObject:afterDelay:
Specify YES for waitUntilDone when sending the message
Both of these solutions are ok, but 1. complicates the test quite a lot, and 2. changes the messaging system I'm writing tests for, so will have to be carefully considered.
Considering what performSelectorOnMainThread:withObject:waitUntilDone:YES does, it seems like the functionality I'm asking for should be possible (as it's similar in many ways), but is it possible?
This might be what you're looking for:
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
This will execute one iteration of the main run loop and then continue on from there. This is kind of abusing the way the run loop is supposed to work though, so you might want to consider a different design - it's almost never a good idea to pause the main thread. Maybe do what you need to do in a separate thread and have that thread call back to a delegate method when it's done, or use a notification.
Use multithreading for this purpose. SENDER on the mainThread, WATCHER on a secondThread, what allows you to start WATCHING before SENDING.
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.
I am working on an app, which uploads native contacts to server then get responses(JSON, a contact list that already installed the app). When native contacts are large enough, server response will be slow and unstable. And user cannot do other things. so I put network request into background thread. every time I will upload 100 contacts, do some tasks , then next 100 contacts until loop finish.
But in running, the result is not as expected. background thread is running, it keeps to request server. UI thread is blocked, I still cannot do anything.
is this cause a long loop in background thread? Although I have 2 thread, but they will compete CPU resources(test device is iPod, 1 core. And I think this may not related core numbers)?
Could anyone tell me hints on how to handle this kind of scenario? Thanks in advance!
Update:
I have found the root cause. A global variable in App delegate is set to wrong value, therefore UI behavior is weird. I found this by comment all network request method. So this problem is not related with multiple threading. Sorry for the bother.
I think there needs to be some clarification as to how you are performing the network operations.
1st, NSOperatiomQueue deals with NSOperations, so you are presumably wrapping your network code in an NSOperation subclass.
2nd, are you using NSURLConnections for your networking code?
3rd, is the blocking part the NSURLConnection or you delegate callback for NSURLConnection?
1 thing to note is that plain ol' NSURLConnections are implemented under the hood multithreaded. The object is placed into your main threads run loop by default (when run from the main thread), but the object is just a wrapper that handles callbacks to the delegate from the lower level networking code (BSD sockets) which happens on another thread.
You really shouldn't be able to block your UI with NSURLConnections on the main thread, unless A) you are blocking the thread with expensive code in the delegate callback methods or B) you are overwhelming your run loop with too many simultaneous URL connections (which is where NSOperationQueue's setMaxConcurrentOperationsCount: comes into play)