I want to call a method from elsewhere in the app to get the user's location that was obtained in the app delegate. When calling CLLocation *getCurLoc = [AppDelegate getCurrentLocation];
from another view controller, nothing is returned.
The App Delegate is,
@synthesize locationManager;
CLLocation *location;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
locationManager.desiredAccuracy=kCLLocationAccuracyKilometer;
[locationManager startUpdatingLocation];
return YES;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
[locations lastObject];
[manager stopUpdatingLocation];
CLLocation *location = [locations lastObject];
}
+(CLLocation *)getCurrentLocation{
return location;
}
Changing it to an instance method with a "-" didn't work. Should "location" be made into an instance? Should the delegate be made into an instance, or is there a better way to access it from elsewhere?
Martin's answer is an effective quick&dirty way of solving this problem in a way that is consistent with your approach - storing the location in
appDelegate
.If you want to take a step further you might want to consider implementing a special object that would hold the data - the data model. It is considered a bad practice to store data in application delegate - it is not what it is there for (though it works perfectly fine in sample or small applications).
You could do something like this:
DataModel.h
DataModel.m
You would then need to
#import "DataModel.h"
wherever you need it. You would change yourdidUpdateLocations:
to:And from anywhere in the code you could get this location simply by
[DataModel sharedInstance].location
.EDIT:
For a very simple app this approach might look as an overkill. But as soon as your app grows it surely pays off to use it.
This kind of class/object/singleton is ment to hold all the data your app needs (fixed and temporary). So all the data sources can make a good use of it. In short: it enables you to easily follow the model-view-controller guidelines.
You cold of course use another class/object/singleton to hold the temporary data - it depends on the complexity of your data-structure.
You don't have to specifically initialize this kind of object. It is initialized the first time you reference it. That is why
dispatch_once
is there for. It makes sure that there is one and only one instance of this shared object present: https://stackoverflow.com/a/9119089/653513And this one single instance of
[DataModel sharedInstance]
will remain there until your app is terminated.Apple uses similar approach for
[NSUserDefaults standardDefaults], [UIApplication sharedApplicaton]
for example.I tend to put the
#import "DataModel.h"
into my projectsPrefix.pch
so I don't have to import it every single time I use it (it is used trough all the app).PROS: - data accesible throughout the app - code reusability - MVC structure - code is more readable
CONS: - I couldn't really find one. Except that the
dispatch_once(&onceSecurePredicate,^...
might confuse one for the first couple of seconds.You can access the
AppDelegate
from any point in your application using[UIApplication sharedApplication].delegate
so you could do:The method
getCurrentLocation
needs to be an instance method (-(CLLocation *)getCurrentLocation
). You will need also to import#import "YourAppDelegateClassName.h"
in those files you need to use that method.To avoid the casting and accessing
[UIApplication sharedApplication].delegate
everytime I prefer to implement a static method in my AppDelegates:So you can use any method like this:
In
didUpdateLocations
, you define and set a local variablelocation
, not the global variablelocation
defined at the top of the file. Changing the lineto
would fix the problem. But the better solution is to use a property in the AppDelegate class. You can define it in a class extension:
Then you access it in instance methods like
and in a class method like
Update: If the AppDelegate is declared to conform so some protocol (in the public interface or in the class extension), for example:
then the above code creates a warning
and an explicit cast is necessary: