grand central dispatch, operation queues, async, view will and did disappear - ios

Hopefully these questions will seem helpful to people out there. I've been learning objective c, mostly from this book, which I found to be amazing and helpful even for a noob. My questions all have to deal with this:
What happens to the queue when the user changes the view? I can't seem to find a good explanation anywhere.
From my understanding, using the NSOperation and its queue, you can always cancel it using the "cancel"...but what if you don't want it to cancel? What if, say a user selects multiple images to upload to the server, and you create a queue with the order, and the user switches to a new view controller? This might be time consuming, especially on a slow mobile network. I remember reading somewhere that iOS gives around 20 seconds extra time for a method to finish its work, but I think that's only when the app enters to the background.
For the GCD, there is no cancel method...so what happens in the background if you use async? I guess if you don't have a response to the queue, I mean you don't update the UI in any way, shouldn't the queue finish since it's sent to another thread?
I'm sure there is much more that I don't understand as far as threading goes, but I hope I made my question clear. And please please don't tell me to use the AFNetworking stuff...I tried using all those keychain wrappers out there and it all failed. Thanks to the book, the straight Apple code from the book did everything easily. I would rather learn the basics first before using the easier way out.
I would really appreciate if someone took the time to talk about this. Thanks in advance!

Your concern about only having a set amount of time to finish tasks only applies to when you switch away from your app to another app. And in that case you can use the beginBackgroundTaskWithExpirationHandler method so your app can request time to finish those tasks if your app happens to go into background. See the Executing a Finite-Length Task in the Background section of the App States and Multitasking section of the iOS App Programming Guide for more information.
But if you're still within your app (whether you transitioned to another view controller or not), anything you've added to your operation queue will continue to run until you cancel those operations (or the app is suspended or terminated). Likewise, anything you've added to a GCD queues will continue to run until the app is suspended or terminated.
In both of these scenarios, the above beginBackgroundTaskWithExpirationHandler will give you a few minutes to finish your queued tasks/operations after your app goes into the background.

Related

Possible to make a task scheduler for iOS?

I want to make an app where I can have a task (GET URL) run at predefined times (selectable in UI). For instance, Monday to Friday at 8am.
Is this possible in iOS?
I tried searching but haven't found anything very useful, probably using the wrong search terms. Does anyone happen to find some sample code for what I'm trying to do?
Edit: Pointing out that I want the app to perform these tasks even if the app is not running. I want to user to just select wanted days of the week and time, and then the phone will take care of everything - even if the phone is restarted.
If you want to regularly wake up to download content, you can register to get push notifications, and download based on the contents of the notification. You are likely to get some cycles to do this close to the scheduled time. If you want to 'opportunistically' download content you can register for background 'fetch' but there is no guarantee of scheduling.
See
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
So, first of all, the app has to be open for any kind of task to run. After that, there are 2 ways you can do it:
You can set a timer with a selector, or you can use grand central dispatch. Both have their strengths and weaknesses depending on what the task is...
https://developer.apple.com/Library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/index.html
https://developer.apple.com/library/ios/documentation/performance/reference/gcd_libdispatch_ref/index.html
check out those links and see if they can help.
Remember that you should do stuff like this on a background thread, and that the UI cannot be updated from any thread by the main thread. Additionally, remember the limitations iOS puts on background applications.
Yes, it is possible.
You can use -
[self performSelector:#selector(myFunc:) withObject:nil afterDelay:5.0];

iOS - app interface freezes up on startup during network calls

The app I am working on fetches a bunch of different newsfeeds when it first starts up and updates any expired ones. While this is happening the interface often freezes up and you can't click anything. The actual network calls are being done on a separate thread, but the database operations are being done on the main thread. Would this cause the interface to freeze?
I have been told that I need to make it to where only two feeds to update are inserted into the network operation queue at a time so that it won't try all of them at once, but it's already set up to only do so many network calls at once. I don't understand how having less things in a queue at a time would cause it to go faster if they're just going to be put in there sequentially anyways. Please correct me if I am wrong, I'm still pretty new to this.
Any kind of help regarding what could cause the UI to freeze up during startup like this would be much appreciated!
It is always a good idea to move time consuming operation away from the main thread.
Fortunately it is pretty simple to do on iOS. If the time-consuming task is fairly simple you could consider using performSelectorInBackground
e.g:
[self performSelectorInBackground:#selector(myFunction:)
withObject:myParam];
It is however important to remberber, that you must not access the GUI from the background thread. To get objects back to the main thread use performSelectorOnMainThread
e.g:
[self performSelectorOnMainThread:#selector(myFunction:) myParamwaitUntilDone:YES];
Try applying this strategy to your database calls. Depending on your scenario you might want to wrap it up in a NSOperation or use a Thread when the cause of the freeze is found.

Using GCD for offline persistent queue

Right now I have some older code I wrote years ago that allows an iOS app to queue up jobs (sending messages or submitting data to a back-end server, etc...) when the user is offline. When the user comes back online the tasks are run. If the app goes into the background or is terminated the queue is serialized and then loaded back when the app is launched again. I've subclassed NSOperationQueue and my jobs are subclasses of NSOperation. This gives me the flexibility of having a data structure provided for me that I can subclass directly (the operation queue) and by subclassing NSOperation I can easily requeue if my task fails (server is down, etc...).
I will very likely leave this as it is, because if it's not broke don't fix it, right? Also these are very lightweight operations and I don't expect in the current app I'm working on for there to be very many tasks queued at any given time. However I know there is some extra overhead with using NSOperation rather than using GCD directly.
I don't believe I could subclass a dispatch queue the way I can an NSOperationQueue, so there would be extra code overheard for me to maintain my own data structure and load this into & out of a dispatch queue each time the app is sent to the background, right? Also not sure how I'd handle requeueing the job if it fails. Right now if I get a HTTP 500 response from the server, for example, in my operation code I send a notification with a deep copy of the failed NSOperation object. My custom operation queue picks this notification up and adds the task to itself. Not sure how of if I'd be able to do something similar with GCD. I would also need an easy way to cancel all operations or suspend the queue when network connectivity is lost then reactivate when network access is regained.
Just hoping to get some thoughts, opinions and ideas from others who might have done something similar or are more familiar with GCD than I am.
Also worth noting I know there's some new background task support coming in iOS 7 but it will likely be a while before that will be my deployment target. I am also not sure yet if it would exactly do what I need, so at the moment just looking at the possibility of GCD.
Thanks.
If NSOperation vs submitting blocks to GCD ever shows up as measurable overhead, the problem isn't that you're using NSOperation, it's that your operations are far too granular. I would expect this overhead to be effectively unmeasurable in any real-world situation. (Sure, you could contrive a test harness to measure the overhead, but only by making operations that did effectively nothing.)
Use the highest level of abstraction that gets the job done. Move down only when hard data tells you that you should.

Using GCD or not?

I have an iPhone app which pretty much is a mobile app for a website. Pretty much everything it does is call API methods from our server. The app retrieves the user's information, and keeps updating the server using the API.
My colleague and I had a discussion whether to introduce GCD to the downloading aspect on the app. My colleague argues that since the UI needs to wait for the download to complete before it can display the pictures, text or whatever, there is absolutely no need for GCD. My argument is that we should keep the main thread busy with UI rendering (even if there is no data), and introduce GCD to the app to create other threads for download.
Which argument is right here? In my case, if the UI renders with no data, will there be some sort of lag? Which will yield a cleaner, sleeker and faster app?
One argument would be : what will happen when the download fails and times out because there is a problem at the server end ?
Without GCD the app will remain blocked and will crash after a time
out since the UI can not be blocked for longer than 20 seconds.
With GCD the application remains functional but there will be no data
being downloaded and the application will not crash.
Other aspects to take into account are :
the thread safety of the objects that you are using
how you handle downloads that are no longer necessary because the user navigates away from the page
I don't think doing time consuming operations in the main thread is a good idea.
Even if user have to wait for the data te be downloaded before he can do anything meaningful, still he will not hope UI is blocked.
Let's assume you have a navigator view, and after user tap some button, you push a new view to it and start download something. If user suddenly decides he don't want to wait anymore, he tap the "back" button. If your downloading operation blocks UI, user will have to wait it to end, it's really bad.
A more appropriate question would perhaps be if you should download asynchronously or on the main thread for your app, since there are several different methods to download asynchronously on iOS (e.g. using NSThread, NSOperation or indeed GCD). An easy approach to achieve your goals could be to use the AFNetworking library. It makes multithreaded networking / internet code very easy to implement and understand.
Personally I'm very fond of GCD and recommend you learn it someday soon, though in itself it is not as suitable for asynchronous downloading compared to a library like AFNetworking (that uses GCD under the hood, I believe).
Here is a good read on using NSOperationQueues (that uses GCD behind the scenes) to download images. There is also some Github code you can check out. They have an elegant solution to pause downloads and enqueue new downloads when the user moves to different parts of your app.
http://eng.alphonsolabs.com/concurrent-downloads-using-nsoperationqueues/?utm_medium=referral&utm_source=pulsenews
Use GCD / NSOperationQueues as opposed to using NSThreads. You will have a good learning on core fundamentals and at the same time create a well architectured app. :)

How to do lengthy operations without being killed by the watchdog? iphone

I have an important operation that is executed rarely. In some cases, it might take minutes to execute. My app is getting killed after a 50 second operation. How to avoid that?
Should I put it in a background thread? Could anyone please point me in the right direction here. I have not found any useful information about the so called watchdog. Is a background thread the way to go?
Yes, you need to move this task to a background thread. You should never jam up the main thread with any task that takes longer than a fraction of a second to perform. Ignoring the watchdog timer, which only kicks in under extreme conditions, your application is completely unresponsive to touch or other events during this lengthy operation, and you're unable to provide feedback to the user as to the progression of this operation.
The watchdog timer will kill an application that jams up the main thread for an extremely long period of time, making the application unresponsive to input (I believe this duration is currently 20 seconds on startup, but I'm not sure what it is for when the application is running). You should never let your application get to the point where the watchdog is killing it, because that's pointing to a real problem in the way your application is handling things.
Moving a long-running task to a background thread is a lengthy topic by itself, which is why I recommend reading Apple's Concurrency Programming Guide (updated) as well as watching some of their WWDC videos on the subject before starting.
However, in my opinion the most elegant way to deal with long-running tasks is to use Grand Central Dispatch, where something like
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do your long-running task here
dispatch_async(dispatch_get_main_queue(), ^{
// Do callbacks to any UI updates here, like for a status indicator
});
});
will fire off your task to be performed in a background thread on one of the global concurrent queues. The little section of code within the main block shows how you might update any UI elements, such as a progress bar, from within this background task. Generally, UI updates must be performed on the main thread (there are some exceptions as of iOS 4.0, but it's still a good practice in general).
I also highly recommend adding some kind of visual indication of the status of this long-running task as it proceeds. Your users will really appreciate this, and it will make your application appear faster, even though it may run for the same duration.
Can you occasionally hit the watchdog during your process? Watchdog timers are just there to detect whether something crashed. They aren't really concerned with the system being busy.
Is the phone still able to respond to the user doing stuff like pressing the home button during your process?
EDIT: This guys recommends using a background thread

Resources