In my app created NSOperationQueue of NSOperation to download multiple images in background.I wanted to know what will happen if network connection is lost while downloading data.Whether all those are operations which are still in queue are marked as finished and removed from queue or will remain in queue and again start downloading process when network is established again or something else?
Can anyone explain how NSOperationQueue works in such scenario?
Thanks in advance!
The current NSOperation will continue with whatever logic is left when it receives the failure signal, and then terminate as normal, causing the NSOperationQueue to begin running the next NSOperation. If the internet still isn't back, it'll fail as well, and will just keep moving through the queue whether the network re-connects or not, failing all the connections unless the network reconnects.
There's probably quite a few different ways to handle this, because there's a lot to consider. For instance, you could put some logic in your code to mark an NSOperation as unsuccessful if it fails due to a network drop-out, and re-add failed NSOperations back into the queue. However, what if the network stays down for ages? Would your implementation be okay to keep trying to download images forever, or should you only let it re-try a particular file download a few times before giving up until the next time that feature is used?
You could also use a series of network reachability checks, such as before an NSOperation is added to the queue, before the NSOperation itself launches the NSURLConnection, etc. Should it fail you could have the NSOperation wait around until the network is re-connected and continue. (It's not ideal to do that, but because you're running it on a background thread it won't freeze the app's interface for the user at least).
If you wanted to, you could even implement the functionality you asked about in your question. That is, upon a network drop-out, cancelling all remaining operations in the NSOperationQueue, informing the user they'll have to re-try when the net comes back on. Then the next time the feature is called, re-add all those remaining NSOperations.
Related
I have a high-priority audio thread that runs periodically and should do minimal synchronization.
Sometimes the main thread needs to ensure that at least one audio cycle has passed and certain parameters have been picked up, before sending the next batch of parameters. For example, when disabling an audio node the main thread needs to wait until the next cycle when the disabling command is picked up and the node shuts itself down.
At times it is important for the main thread to wait until the command is fully executed, but other times it's not important, so nobody might be listening to the sync event. Hence the "lossy" scenario.
So what is the best way of notifying other threads about an event with minimal overhead and possibly in a "lossy" way?
Can't think of ways of using a semaphore for this task. Are there any canonical ways of achieving this? Looks like Java's notifyAll() works precisely this way, if so, what synchronization mechanism is used behind notifyAll()?
Edit: been thinking, is there such a thing as "send me a semaphore in a queue and I'll signal it"? Seems a bit too complicated but theoretically it could do the job. Any simpler tools for the same task?
As a rule, you never want to block the main thread (or, at least, for more than a few milliseconds). If the response might ever take longer than that, rather than actually waiting, we would adopt asynchronous patterns, let the main thread proceed. Sure, if you need to prevent user interaction, we’d do that, but we wouldn't block the main thread.
The key concern is that if an app blocks the main thread for too long, you have a bad UX (where the app appears to freeze) and you risk having your app killed by the watchdog process. I would therefore not advise using semaphores (or any other similar mechanisms) to have the main thread wait for something from your audio engine controller.
So, for example, let’s say the main thread wants to tell the audio engine to pause playback, but you want the UI to “wait” for it to be acknowledged and handled. Instead of actually waiting, we would set up some asynchronous pattern where the main thread notifies the audio engine that it wants it to pause, the audio controller would then notify the main thread when that request has been processed via some callback mechanism (e.g., via delegate protocol pattern, completion handler closure, etc.). If you happen to need to prevent user interaction during the intervening time, then you’d disable controller and use some UIActivityIndicatorView (i.e., a spinner) or something like that, something that would be removed when the completion handler is called.
Now, you used the term “lossy”, but that generally conveys that you don't mind the request getting lost. But I’m assuming that is not really the case. I'm assuming that you don't really want the request to be lost, but rather only that the main thread doesn't care about the response, confident that the audio controller will get to it when it can. In that case, you'd probably still give this sort of request to the audio controller a callback mechanism, but the main thread just wouldn’t avail itself of it.
Now if you have a sequence of commands that you want the audio engine to process in order, then the audio controller might have a private, internal queue for these requests, where you’d configure it to not start subsequent request(s) until the prior ones finished. The main thread shouldn't be worried about whether the required audio cycle has processed. It should just send whatever requests are appropriate and the audio controller should handle them in the desired order/timing.
For performance reasons, I instantiate a dedicated NSThread to process incoming messages that are streamed from a network server. I use an NSOperation for the purpose of instantiating the connection and receiving incoming data through the NSURLConnection delegates, but as soon as new data comes in and gets parsed, I offload the processing of the message to the dedicated NSThread. The idea is to let one thread focus on receiving incoming messages and let the other thread just do the processing.
What's the proper way to shut down the NSThread when the applicationDidEnterBackground comes in?
Also, how should I restart the NSThread when applicationWillEnterForeground comes in?
Other than the main thread, it seems the state of other background threads is not maintained between going to sleep and restarting.
By the way, I'm all for using NSOperations for most tasks that have a measurable amount of work -- ie, accessing a resource over the network, performing a calculation, etc. However, in this case, I need to process messages on the fly on a long-living dedicated thread that is always there by calling performSelector:onThread:withObject:waitUntilDone: and passing it the target thread. It seems NSOperation isn't a good fit for this.
I would appreciate your input.
"For performance reasons"?
If processing doesn't take much time, run everything (including NSURLConnection) on the main thread. Concurrency bugs are a major pain.
If you want things to run serially, you can emulate a "single thread" with an NSOperationQueue with maxConcurrentOperations = 1. I'm pretty sure that NSOperationQueue uses thread pools (and on 4.0, GCD, which probably uses thread pools), which means you don't need to keep a thread running all the time.
Apart from that, your process is automatically suspended and resumed by the system, so you don't need to kill off threads.
I'm not sure what you mean by "the state of other background threads".
I have an app that needs to upload a least 5 photos to a server using API call available with the server. For that I am planning to use threads which will take care of photo upload and the main process can go on with the navigation of views etc. What I cant decide is whether it is OK to spawn five separate threads in iphone or use a single thread that will do the upload. In the later cases obviously it will become quite slow.
Basically an HTTP POST request will be made to the server with the NSMutableURLRequest object using NSCOnnection.
More threads mean more complexity and sync issues, but I can try to write code as neat as possible if it means better performance than a single thread which is simple but is a real stopper if performance is considered.
Anybody with any experience in this kinda app. ??
I would suggest using one extra thread and queuing the uploads, one after the other. You'll end up clogging the network interfaces if you try 5 uploads concurrently. Remember that the iPhone will often be on a 3G or even EDGE connection, not always WiFi, so photo uploads can be really slow, and even slower if there are 5 at once.
You could probably benefit from using NSOperation and NSOperationQueue to nicely handle the ugly threading for you. Wrap up an upload process into an NSOperation, and then queue 5 of them for each image. Should work quite nicely.
Jasarien thanks for the bit on NSOperation and NSOperationQueue. It did simplyify in great measure. But right now I hve run into a major issue.
I spawn an extra thread from the main thread. This thread queues up each of the picture upload operation. So this thread queues up 5 picture opload operations in a queue. This is absolutely fine when working with Mac PC. Now when I push the app to the device, only one pic upload is successful and the rest fails. Most of the cases of failure are due to server time out error. So basically I am wondering, whether NSOperationQueue ensure only one operation at a time or not ? I mean if the first pic upload is in progress and say the next operation is already added in the queue. Would it create an extra thread for the second operation too while the first one is running ? I think as the name suggests, it must wait in the queue until the previous one is done. Not sure how to go abt doing it. I am uploading pic which are taken with iphone camera.
My iPhone application supports a proprietary network protocol using the CocoaAsyncSocket library. I need to be able to send a network message out when my iPhone application is closed. The code that sends the message is getting called from the app delegate, but the application shuts down before the message actually goes out. Is there a way to keep the application alive long enough for the message to go out?
Bruce
The docs from Apple don't specifically state this, but the sense I get from looking around the Web and from personal experience is that you have about 4 to 5 seconds after the user hits the Home button to shut your app before your application actually terminates. The iPhone OS is controlling this so you can't block the termination to allow your program to finish first. Basically when your time is up, your program is killed.
There may be another solution, though. First I'd confirm that your code is really taking more than 5 seconds to run. Perhaps you can have it run in response to a button tap, and time how long it runs. If it is more than 5 seconds, you probably are running into this time out issue.
You might then find a way to trigger a message to be sent from a server that is always running. You should have enough time to trigger a remote action, which in turn could then take as long as it needs to run.
Or perhaps you could save the vital information to the iPhone file system on exit, and send that message the next time someone starts the application, which should theoretically give you enough time.
Hope this helps!
I assume you're already calling it from your AppDelegate's:
- (void)applicationWillTerminate:(UIApplication *)application
But as you've discovered there's no guarantee it'll be called or will be allowed to finish. There are a few options that may or may not work depending on what you're trying to do:
If you need the server to perform some sort of cleaning operation triggered by when the client app is gone then you could try watching for TCP socket closure on the server and treating that as the triggering event. But if you explicitly need to send data back with the closure this may not work.
If the data you're sending back is not time-sensitive then you can do like most of the analytics libraries do and cache the data (along with a uuid) on the client then try to send it on app closure. If it goes through, you can clear the cache (or do it the next time the app is run). If it doesn't, it's saved and you can send out when the app is run next. On the server, you would use the uuid to avoid duplicate requests.
If the material is time-sensitive then your best bet is to implement heartbeat and send periodic updated values to the server. Then when the client app dies the server times out the heartbeat and can use the last received value as the final closing point of data.
In either case, if an explicit closure event is required by your custom protocol then you may want to reconsider using it in a real-life mobile environment where things have to be much more fluid and tolerant of failure.
As others have noted, there's no way to be absolutely certain that you'll be able to send this, but there are approaches to help.
As Ken notes, you do in practice get a few seconds between "willTerminate" and forced termination, so there generally is time to do what you need.
A problem you're almost certainly running into is with CocoaAsyncSocket. When you get the "willTerminate" message, you're on the last run loop of the main thread. So if you block the main thread, and CocoaAsyncSocket is running on the main thread, it'll never get processed. As I recall, CocoaAsyncSocket won't actually send all the data until the next event loop.
One approach, therefore, is to keep pumping the event loop yourself:
- (void)applicationWillTerminate:(UIApplication *)application
{
// ...Send your message with CocoaAsyncSocket...
while (! ...test to see if it sent...)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
I've also looked at putting this work onto a background thread and letting the main thread terminate, in theory letting us go back to Springboard while continuing to run for a few seconds. It's not immediately clear to me whether this will work properly using NSThread (which are detached). Using POSIX threads (which are joinable by default) may work, but probably circumvents any advantages of the background thread. Anyway, it's something to look at if useful. In my apps, we've used the "post next time we launch" approach, since that always works (even if you crash).
i am getting confused what is the difference between Synchronous NSUrlConnection and ASynchronous NSUrlConnection?is there Synchronous or ASynchronous? if we use detachNewThreadSelector in connectionDidFinishLoading method,is it
ASynchronous NSUrlConnection? which is the best way?any tutorial ...
Synchronous means that you trigger your NSURLConnection request and wait for it to be done.
Asynchronous means that you can trigger the request and do other stuff while NSURLConnection downloads data.
Which is "best"?
Synchronous is very straightforward: you set it up, fire it, and wait for the data to come back. But your application sits there and does nothing until all the data is downloaded, some error occurs, or the request times out. If you're dealing with anything more than a small amount of data, your user will sit there waiting, which will not make for a good user experience.
Asynchronous requires just a little more work, but your user can do other stuff while the request does its thing, which is usually preferable. You set up some delegate methods that let you keep track of data as it comes in, which is useful for tracking download progress. This approach is probably better for most usage cases.
You can do both synchronous and asynchronous requests with NSURLConnection. Apple's documentation provides a clear explanation of the two approaches and delegate methods required for the latter approach.
It seems that you're conflating synchronous/asynchronous connections and threading. In my app I used asynchronous connections as an alternative to threading.
Let's say you want to download a big file without causing the UI to freeze. You have two basic options:
Asynchronous connection. You start with + connectionWithRequest:delegate: (or one of the other non-autorelease options) and it downloads bits of the file, calling your delegate when interesting thing happen. The runloop is still going, so your UI stays responsive. Of course you have to be careful that your delegate don't go out of scope.
Synchronous. You start the connection with + sendSynchronousRequest:returningResponse:error: but the code waits until the download is complete. You'll really need to spawn a new thread (or one of the higher level threading operations that Cocoa supports) or the UI will block.
Which option is "best" or the least painful will depend on the architecture of your application and what you're trying to achieve. If you need to create a thread for a long running process anyway, you might go with the second option. In general I would say the first option is easiest.
It's all pretty well documented on Apple's Developer site.
Something which hasn't been mentioned in the other responses is the size of the request. If you're downloading a large file, for example, then using an asynchronous connection is better. Your delegate will receive blocks of data as they arrive. In comparison, the synchronous method will wait for all the data before making it available to you. The delegate can start processing the response sooner (better user experience), or save save it to a file instead of memory (better resource usage). You also have the option to stop the response without waiting for all the data.
Basically, the asynchronous method gives you more control over the connection but at the cost of complexity. The synchronous method is much simpler, but shouldn't be used on the main UI thread because it blocks.
In response to the other answers regarding the file size: I think file size doesn't matter. If the server responds really slowly and you're loading data synchronous your UI still freezes, even if you're loading a small amount of data, like 3k.
So I'd go for the asynchronous option in every situation, cause you never know what you're going to get with regards to file size, server responsiveness or network speeds.