According to the documentation of CLLocationManagerDelegate
The methods of your delegate object are called from the thread in which you started the corresponding location services. That thread must itself have an active run loop, like the one found in your application’s main thread.
I am not clear as to whether this means that to receive location manager updates on a background thread, we must instantiate the location manager on that background thread or simply call the startUpdatingLocation()
method on that thread.
In any event, this explains an issue when a CLLocationManagerDelegate
does not receive any events from a CLLocationManager
which was started on a background thread:
That thread must itself have an active run loop
If I understand run loop functioning correctly, all NSThreads
are instantiated with a run loop, but the run loop will only be running if you assign some work to the thread. Therefore, to have a CLLocationManager
send events correctly on a background thread, we need to set the thread's run loop to loop permanently so that it can process the CLLocationManager
's calls as they arrive.
A reasonable solution to making sure the run loop is running is suggested in this question but the author implies that this is a processor expensive way of doing it.
Also, according to the threading documentation,
Threading has a real cost to your program (and the system) in terms of memory use and performance
I appreciate that we are all using lots of threading anyway, by using Grand Central Dispatch, but Grand Central Dispatch probably mitigates a lot of this in its internal thread management.
So my first question is, is it worthwhile setting up a background thread with a continuously running run loop, in order to have location events dealt with on a background thread, or will this involve an unreasonable extra amount of processing when compared to leaving the manager on the main thread?
Secondly, if it is worthwhile, is there a good way to do this using Grand Central Dispatch. As I understand the documentation, Grand Central Dispatch manages its own threads and we have no means of knowing which thread a given block will be executed on. I presume we could simply execute the usual run loop code to make the run loop of whichever thread our CLLocationManager
instantiation is run on loop continuously, but might this not then affect other tasks independently assigned to Grand Central Dispatch?
This is a somewhat opinion-based question, but I have a pretty strong opinion on it :D
No.
Just deliver the events to the main queue, and dispatch any work to a background queue if it's non-trivial. Anything else is a lot of complexity for little benefit. CLLocationManager pre-dates GCD, so this was useful information in the days when we occasionally managed run loops by hand and dispatching from one thread to another was a pain. GCD gets rid of most of that, and is absolutely the tool you should use for this. Just let GCD handle it with dispatch_async
.
You absolutely should not set up your own NSThread
for this kind of thing. They're still necessary at times for interacting with C++, but generally if GCD can handle something, you should let it, and avoid NSThread
as much as possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With