When close view that started locations service notification error occure - ios

I have created small app that use this project as it's core:
https://github.com/dsdavids/TTLocationHandler
And it worked fine until I have moved stating location services from another view in app.
What app is doing: When it is started you can tap on START button and (in emulator locations must be enabled) on the map route of movement is displayed as you move.
The problem came when I moved starting action in a second view.
In that second view I just want to start location service and close it.
The problem is when I start locating on the second view I get error (application crash EXC_BAD) here:
TTLocationHandler
...
dispatch_async(dispatch_get_main_queue(), ^{
if (OUTPUT_LOGS) NSLog(#"Sending notification out");
NSNotification *aNotification = [NSNotification notificationWithName:LocationHandlerDidUpdateLocation object:[locationToSave copy]];
[[NSNotificationCenter defaultCenter] postNotification:aNotification];
});
...
I think that it is because I close the second view (view that started service) and TTLocationHandler still tries to send it something.
For better understanding my problem I have added project at git hub:
https://github.com/1110/common-location-features
You can download it and run start service from second view and when close that view app will crash in a few seconds.
I would be really thankful if someone can find a little time to tell me what am I doing wrong here as I am sure that it is some small thing that I probably doing wrong.
Whole code is in SecondViewController.m
Thanks

The problem is probably that the location manager is sending location updates to an object that no longer exists.
I don't have the time to dig through all of your code, but generally speaking once you tell the location manager to startUpdatingLocation, you need to keep your location manager delegate object around until you tell it to stop. If what you refer to as the "second view" is your delegate object, then you can't let that view get deallocated until you tell the location manager to stopUpdatingLocation.
Generally you want to have one object be the CLLocationManagerDelegate, and keep that object around for as long as you need it. The delegate will get notified every time the location changes, and it is the delegate's responsibility to update any views that care about the location.

Related

How to wait for CLLocationManager w/o stalling app nor accessing UIView from background thread?

I'm trying to figure out the right approach to wait for location data to become available, before adding/drawing subview/sublayers without blocking the main thread. E.g. I want to draw views based on long/lat of current location of current user that authorized such.
I have a CLLocationManager related object that does the configuration and waits for a callback from the OS with long/lat.
I want to display something in a UIViewController (that is one of the main tab bar items), but only after the location becomes available and my location function gets the callback from iOS.
But it seems to be a Catch-22. If I try waiting on the main thread, of course it blocks everything, but if I wait for the data on a background thread, I can't tamper with UIViews from that thread.
How can this be handled?
When you request location information (e.g., startUpdatingLocation), you may not receive location information immediately. So you need to decide what you want to show in your UI in the intervening period of time. A blank/blurring view with a spinner (e.g., UIActivityIndicatorView) on top of it? Maybe save the last known location in persistent storage so that when the user fires up the app again, they at least see information relevant to the last known position until new location information comes in?
But we never block the main thread (which will only freeze the app, leading the user to suspect that the app died, and we risk having the watchdog process kill our app). Instead, we avoid blocking the main thread and just decide what UX we want to show until the location information is retrieved. And when the new location information comes in, we replace the placeholder content with a UI that represents the action location information.

Where to put code that gets checked frequently?

I have some code that needs to get called frequently, such as check what day it is, if it's the next day then move the day strings in the tableView.
Now I thought that the viewDidLoad would get called all the time and so it would be 'fine' to put it in there. However, I've left the simulator overnight, and I've pressed the home button and clicked again, changed VCs etc. and viewDidLoad hasn't been hit.
What are my options for doing sporadic checks such as, is it a new day? As x happened etc.
In this specific case, you can subscribe to NSCalendarDayChangedNotification to be notified when the date changes and respond accordingly in your view controller. In general, didBecomeActive or viewDidAppear would likely work.
What are my options for doing sporadic checks such as, is it a new day
It depends what the meaning of "is" is! In particular, "is" when? You say "sporadic", but that's just fluff. When do you need to know this? To what stimulus do you want to respond? When the user opens your app? Then put it in applicationDidBecomeActive. Every day at noon? Then run an NSTimer. Really, the problem here is that you don't seem to know, yourself, just when you need to perform these checks.
Whilst in your app, its quite easy to continually check for something. You simply create a background thread. However, what you describe is a thread that persists from outside the app's lifecycle.
Have a read on this documentation provided by Apple itself. You have to have good excuse to put a background thread. The scope of such thread is limited to only certain scenarios such as downloading background stuff, playing sounds etc.
For your scenario, I'd look at applicationDidBecomeActive(_:) found in your Application Delegate. There you can mimic such continual check. Beware however, don't put heavy word load on start up or your app might be killed automatically if it fails to become active in reasonable amount of time.

Getting current location but only once

In my ViewController I need to update to current location on viewDidLoad just to download right data from server. Data should be downloaded only once just to fill the tableView but user has right to pull-to-refresh which will get the current location and call reloadData.
I don't want this data to be reloaded automatically when locationManager:didUpdateLocations: method is called what is the cleanest way to refill the tableView. another soultion is KVO on currentLocation but the results are the same - need to call reload everytime location is updated. It should be managed by user manually (just like in example above). I don't have any idea how to do this without raloading tableView every time locations are updated.
Any lead in this case would be a big help!
User [locationmanager stopUpdatingLocation] in locationManager:didUpdateLocations: and on pulltorefresh [locationmanager startUpdatingLocation].
To update a particular cell you can find the reference from the table view and try to get the reference of the control to update that
Hope it will help you.
Accepted answer is the right one for my purpose and it's totally sufficient but... Ifanyone ever would be interested in ready soultion which is clean, nice and supports Cocoapods you should try INTULocationManager.
This little library gives you a pretty handy methods which will wait for your localization or give you back the best possible result. Everything packed in nice block syntax.

How to get GPS coords on button click ? (most simple)

i tried to implement GPS functionality into my app using the few tutorials.
I do it by using this:
http://www.tutorialspoint.com/ios/ios_location_handling.htm
Gps coords are obtained after start of the app.
But problem is that, i am not able to call GPS coords again after button click, it means somethong like:
- (IBAction)getGpsCoords:(id)sender {
[[LocationHandler getSharedInstance]setDelegate:self];
[[LocationHandler getSharedInstance]startUpdating];
}
How should be right solution? I will glad id somebody can explain how to do it better (with some good example or link).
Thanks for any advice.
It's not really clear what you're having difficulty doing. You don't say what LocationHandler is, but the flow is pretty much correct:
Start location services
A delegate method gets called periodically as the location information changes
You can't just tap a button and get the current location; that's not how the API works. I suppose you could start location services when the app starts and record the current location in a singleton (like your LocationHandler class?) and just call that when you press the button?

Which class should be responsible for activity indications when both model and controller need to display it?

I have a model which can download data from a server and thus an activity indicator needs to be displayed (both in the status bar and on screen).
But I also have a UIWebView which is displaying content, the content has links, some are local and some are remote, if a remote link needs to be downloaded then an activity indicator needs to be displayed again.
What are design options for accomplishing this?
The app delegate could have methods to start and stop the activity indicators as directed by the models and controllers. But somehow this doesn't seem quite clean to me - its starting to use the app delegate just as a bucket for dumping miscellaneous functionality.
I'm thinking the model should deal with its own activity indication and the controllers should deal with their own, i.e. separate them. However if I did that wouldn't we then have the situation where a model is doing some UI related stuff (even if minimal)?
Is there a clean recommended solution?
IMO, Activity indicator is a View component independent of a specific view therefore it should be managed by your application delegate.
The way I tackled it is I created an ActivityManager class and I create and instance in my application delegate. It takes an instance of UIWindow and from that, I can determine how to center and display the indicator appropriately. All other areas of my application interact with this class through the observer pattern. They post notifications when the network state has changed and my activity manager evaluates the overall state of the application to see if it needs to either show or hide the indicator. Here is a sample of what you might see in my app:
ActivityManager *activityManager = [[ActivityManager alloc] initWithWindow:self.window];
self.activityManager = activityManager;
[activityManager release];
[self.activityManager addNotification:kNetworkStatusDidChangeNotification];
[self.activityManager addAsyncActivity:[HttpManager defaultManager]];
[self.activityManager startObserving];
I've added the ability to add new notifications so that way, when the manager observes these notification is can evaluate what needs to happen. AsyncActivity is just a protocol for singletons I can check to see if they are processing data. Then I just tell my manager to start observing. When I close my app I simply call:
[self.activityManager stopObserving];
to remove all observers and free up any memory. That should get you started in the right direction, I'm sure there are other ways to do it but that seems like the least invasive way to handle it to me. It's also very portable.
It sounds like there could be multiple network events occurring simultaneously that all need to report activity accurately. Perhaps a separate class that is only responsible for tracking network operations and communicating with your instance of UIApplication is in order.
Imagine an object that uses a simple counter to keep track of the number of network operations. Adding an event increments the counter and removing one decrements the counter. While the counter is > 0, the spinner is visible. This may be a reasonable approach to encapsulating communication between the application and the model layer.

Resources