Suspending already executing task NSOperationQueue - ios

I have problem suspending the current task being executed, I have tried to set NSOperationQueue setSuspended=YES for pausing and setSuspended=NO for resuming the process.
According to apple docs I can not suspend already executing task.
If you want to issue a temporary halt to the execution of operations, you can suspend the corresponding operation queue using the setSuspended: method. Suspending a queue does not cause already executing operations to pause in the middle of their tasks. It simply prevents new operations from being scheduled for execution. You might suspend a queue in response to a user request to pause any ongoing work, because the expectation is that the user might eventually want to resume that work.
My app needs to suspend the time taking upload operation in case of internet unavailability and finally resume the same operation once internet is available. Is there any work around for this? or I just need to start the currently executing task from zero?

I think you need to start from zero. otherwise two problems will come there. If you resume the current uploading you cant assure that you are not missed any packets or not. At the same time if the connection available after a long period of time, server may delete the data that you uploaded previously because of the incomplete operation.

Whether or not you can resume or pause a operation queue is not your issue here...
If it worked like you imagined it could (and it doesn't) when you get back to servicing the TCP connection it may very well be in a bad state, it could have timed out, closed remotely...
you will want to find out what your server supports and use the parts of a REST (or similar) service to resume a stalled upload on a brand new fresh connection.
If you haven't yet, print out this and put it on the walls of your cube, make t-shirts for your family members to wear... maybe add it as a screensaver?

Related

FreeRTOS: two tasks with interrupt

I'm completely new with FreeRTOS. I have two tasks: the first one must be performed continuously in the loop and the second one should turn on only after interrupt and after the second one is done it should return to the first one, which needs to start from the beginning(it's important because the first task collects data and if I continue to perform it from the place where I interrupt I will get the trash.).
Can I use Semaphore for it or is there something better? Thank you in advance.
It is not clear what you are asking or what you want to use the semaphore for. Protecting data access by both the interrupt and the first task? Or maybe signaling the first task? From what I can make out it sounds like you want to have a lower priority task running continuously, then when an interrupt occurs have the interrupt handler unblock a higher priority task that will then preempt the lower priority task and execute. Then when it finishes and blocks again the scheduler will naturally continue running the lower priority task. I'm confused by your statement that if you continue executing from where it was interrupted you will get trash though - interrupts always return to where they interrupted.
The most efficient way of unblocking a task from an interrupt would be a direct-to-task notification. I would also recommend reading some of the generic FreeRTOS documentation and books available on the FreeRTOS.org site.

Handling of Alamofire requests as iOS app is terminating

AppDelegate.applicationWillTerminate is called when the application is about to terminate. In this function, I am issuing a network request via Alamofire, to notify the server that the app is terminating. Alamofire's response handler is never invoked. It looks to me like the termination completes before the completion handler is invoked.
Alamofire's completion handlers appear to run on the main thread. I found documentation saying that the app is responsible for draining the main queue: "Although you do not need to create the main dispatch queue, you do need to make sure your application drains it appropriately. For more information on how this queue is managed, see Performing Tasks on the Main Thread." (From https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html) And this is where I am stuck.
How do I drain the main thread? I need to ensure that this last Alamofire request runs before the main thread exits.
Don't worry about “draining” the main thread. The problem is more simple than that. It's just a question of how to do something when your app is leaves the “foreground”/“active” state.
When a user leaves your app to go do something else, it is generally not terminated. It enters a “suspended” state where it remains in memory but does not execute any code. So when the app is suspended, it cannot process your request (but the app isn't yet terminated, either).
There are two approaches to solve this problem.
You could just request a little time to finish your request (see Extending Your App's Background Execution Time). By doing this, your app is not suspended, but temporarily enters a "background" state, where execution can continue for a short period of time.
The advantage of this approach is that it is fairly simple process. Just get background task id before starting the request and you tell it that the background task is done in the Alamofire completion handler.
The disadvantage of this approach is that you only have 30 seconds (previously 3 minutes) for the request to be processed. If you have a good connection, this is generally adequate. But if you don't have a good network connection in that period, the request might never get sent.
The second approach is a little more complicated: You could make your request using a background URLSession. In this scenario, you are effectively telling iOS to take over the handling of this request, and the OS will continue to do so, even if your app is suspends (or later terminated during its natural lifecycle).
But this is much more complicated than the first approach I outlined, and you lose much of the ease and elegance of Alamofire in the process. You can contort yourself to do it (see https://stackoverflow.com/a/26542755/1271826 for an example), but it is far from the obvious and intuitive interface that you're used to with Alamofire. For example, you cannot use the simple response/responseJSON completion handlers. You can only download/upload tasks (no data tasks). You have to write code to handle the OS restarting your app to tell you that the network request was sent (even if you're not doing anything meaningful with this response). Etc.
But the advantage of this more complicated approach is that it is more robust. There's no 3 minute limit to this process. The OS will still take care of sending the request on your behalf whenever connectivity is reestablished. Your app may may even be terminated by that point in time, and the OS will still send the request on your behalf.
Note, neither of these approaches can handle a "force-quit" (e.g. the user double taps on the home button and swipes up to terminate the app). It just handles the normal graceful leaving of the app to go do something else.

NSURLSessionDownloadTask cancelByProducingResumeData vs suspend

I need to pause download tasks and resume it even after app restarted. But I am unsure which method should I use, suspend or cancelByProducingResumeData.
With cancelByProducingResumeData I can get the partially downloaded data and recreate download task with it. However I have to manually manage the data, save it to file, read it back, and recreate the task and ensure the new task doesn't fail.
With suspend, I can pause and resume the download task. But can I resume this task after the app is restarted? I am using background session so tasks are preserved across restart.
cancelByProducingResumeData have requirements for it to work, does those requirements also applies to suspend/resume? Or suspend/resume is only mean for "temporarily suspends a task" as the document said?
You're overthinking the problem. The "resume data" for a download task is not the data that the task has received up to that point. It is a tiny blob of bookkeeping data—the sort of thing that you'd typically throw into an array in NSUserDefaults.
With that said, to answer the original question, a task is only valid within the context of a session. So for a foreground session, once your app quits, the session ceases to exist, so it is no longer possible to gain access to tasks in that session. Therefore, it is not possible to resume a suspended task after you relaunch the app because the task no longer exists (because its session no longer exists).
For a background session, you'd pretty much have to ask somebody on the Foundation Networking team to get an answer to that one, because it depends on the extent to which you can recreate a session after the fact. However, my guess is that it probably won't work there, either, and if it does, you should consider it unsupported.
After some research on apple developer forms, I found this
Tasks suspension is rarely used and, when it is, it's mostly used to temporarily disable callbacks as part of some sort of concurrency control system. That's because a suspended task can still be active on the wire; all that the suspend does is prevent it making progress internally, issuing callbacks, and so on.
OTOH, if you're implementing a long-term pause (for example, the user wants to pause a download), you'd be better off calling -cancelByProducingResumeData:.
So suspend may not actually stop downloading and I should use cancelByProducingResumeData: for long-term pause.

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.

how to schedule after the current thread has terminated?

I am creating a user defined thread library. I use Round-Robin scheduling algorithm and use the context switching method. But, I am unable to know what to do when a thread finishes its execution before the allotted time slot. The program is getting terminated. I actually want to reschedule all the threads, by calling the schedule function when the current thread gets terminated.
I found two ways to overcome this problem.
By calling explicitly thread_exit function at the end of the function that is being executed by the current thread.
By changing the stack contents such that the thread_exit function gets executed after the current function gets terminated.
But I am unable to find how to apply these solutions....
Anybody out there... plz help me...
It sounds like you have a bit of a design flaw. If I'm understanding you correctly, you're trying to implement a solution where you have threads that can be allocated to perform some task and after the task is complete, the thread goes idle waiting for the next task.
If that's true, I think I would design something like a daemon process or service that manages a queue for tasks coming in, a pool of threads responsible for executing the tasks with a controller that listens for new tasks.

Resources