Stop child threads started by `performSelector` on `viewDidDisappear` - ios

To begin, I realise I may be causing this problem by addressing a previous problem incorrectly...
In a ViewController main thread I am starting a background thread to get updated data from a server using:
[self performSelectorInBackground:#selector(sampleTask:) withObject:#"CMD" ];
This process can take 15-30 seconds so in the main thread I display a local cache of the data from a SQLite database (populated from a previous request to the server the last time the view was opened) and reload the table once the sync with the server is finished.
If the user navigates back out of this view before the sync with the server is finished, the background thread keeps running until it is done. This itself isn't a problem, until the user changes their mind and goes back into this view again. If the timing is right, there's two background threads trying to sync data with the server. If the user does this a few times, the thread count can build up. Eventually the app will collapse, if not cause other problems on the device.
Is there a way to stop the created threads on a trigger like viewDidDisappear?
Or should I be writing a lock to a shared resource (e.g. NSUserDefaults) to prevent a new background thread from being started?
Or -- like I mentioned in the first line -- do I have a bad approach to the issue of updating the local cache that is just causing further problems like this one?

I think you can use simple bool valued semaphore which shows that some sync task is performing. So before performing the next similar task you should check that semaphore.
If you recreate your viewcontroller each time you need static class variable common for all instances of your view controller.

performSelector:withObject:afterDelay: does not create a separate thread.
To quote part of the docs on that method:
Invokes a method of the receiver on the current thread using the
default mode after a delay
It uses a timer to trigger your selector after a delay. As such it is subject to the same accuracy limitations as NSTimer. (The method performSelectorInBackground:withObject: does submit your selector on a background thread.)
But back to your question.
You can use the method
cancelPreviousPerformRequestsWithTarget:selector:object:
To cancel a pending call to performSelector:withObject:afterDelay:

Related

Best Life Cycle Method to Place Main Thread-Blocking Operation in Objective-C

My app syncs with a server similar to the Apple Mail app. While the sync takes place on a background thread, because it is hitting Core Data rather hard, I've found it necessary to block interaction with user controls during the sync, lest some other operation hit core data and create problems.
I had been putting the sync in View Will Appear to keep the phone and server in constant sync. However, with larger amounts of data, I'm noticing that the sync is unacceptably long...that is it ties up the thread for five or ten seconds. I tried placing it in viewdidload so it gets called less often but it is still annoying to wait when you have just opened app.
I've noticed that Apple does not sync mail immediately but waits a few seconds so as not to tie up the app at first. This gives you the illusion, you don't have to wait (although in reality you usually do).
I'm wondering if there is a place in the life cycle that would be better for syncing such as viewdidappear and also whether there is a way to use a delay to launch the sync five or ten seconds after you are in the view controller when it's less conspicuous.
Thanks in advance for any suggestions.
Firstly blocking the main thread isn't preferred under any circumstances for asynchronous operations , as the user will think that the app is hanging and will quit it
Secondly viewDidAppear is meant for updates when say it's in a vc that navigation returns to with back to refresh content or dismissing a model , other than those 2 things it will act like viewDidLoad with the overhead of delay
Finally if you need to sync the mails with server you have 2 options
grab data every fixed time ( not recommeneded ) say with a timer
use silent push notification to notify the app with server new content and initiating the pull process upon receiving it

On iOS, can you begin work on the background thread before applicationDidEnterBackground is called?

I'm updating some content in my app and I want that to finish up when the user switches out of the app. It seems like I have to stop my currently-running update and start another one in the applicationDidEnterBackground method. It would be much more convenient if I could mark some work as something I want to run in the background before that method is called.
Here's the scenario:
I'm trying to update content and start running a SQL update that takes a bit of time. (More than the five seconds you have to return from applicationDidEnterBackground.)
The user leaves the app. The current update is suspended, but I really want it to finish.
I can start a new update which picks up where the other left off, but if the user switches back into the app I have SQL-level concurrency issues.
Is the only option to break down the SQL queries to smaller batches so I can switch over cleanly in the applicationDidEnterBackground callback? It almost doubles the execution time. (I'm not worried about the OS killing my background task, resume is handled fine.)
Ideally I'd be able to have the existing work continue seamlessly in the background (at the pleasure of the OS), is that possible? Are there better options?
(I've read the Programming Guide's section on executing background tasks.)
You can continue to run your current threads. You don't have to stop any of them and start new one.
The only thing which you need to do, if to use beginBackgroundTaskWithExpirationHandler (as proxi mentioned) when you entering background and use endBackgroundTask when you are done. This method gives your application up to 10 minutes of execution. UI of your application won't be accessible (since a user switched to another app), but all threads of your app will continue to run. System will pause all threads when your will do endBackgroundTask or 10 minutes will expire.
I would organize it like this
Have you processing threads running
In applicationDidEnterBackground call beginBackgroundTaskWithExpirationHandler.
Save UIBackgroundTaskIdentifier somewhere accessbile.
At the end of your processing thread, check whether UIBackgroundTaskIdentifier isn't 0 and if it's not, call endBackgroundTask. Set UIBackgroundTaskIdentifier to zero.
If I understand right, you just have to wrap your long-running operation into beginBackgroundTaskWithExpirationHandler block. See the method's documentation for details on how to use it.

Accessing thread from other rails controller action

I'm working on an application, but at the moment I'm stuck on multithreading with rails.
I have the following situation: when some action occurs (it could be after a user clicks a button or when a scheduled task fires off), I'm starting a separate thread which parses some websites until the moment when I have to receive the SMS-code to continue parsing. At this moment I make Thread.stop.
The SMS-code comes as a POST request to some of my controllers. So I want to pass it to my stopped thread and continue its job.
But how can I access that thread?
Where is the best place to keep a link to that thread?
So how can I handle multithreading? There may be a situation when there'll be a lot of threads and a lot of SMS requests, and I need to somehow correlate them.
For all real purposes you can't, but you can have that other thread 'report' its status.
You can use redis-objects to create either a lock object using redis as its flag, create some type of counter, or just true, false value store. You can then query redis to see the corresponding state of the other thread, and exit if needed.
https://github.com/nateware/redis-objects
The cool part about this is it not only works between threads, but between applications.

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.

why my background working thread is blocking UI thread?

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)

Resources