Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Thomas Nilsen
Thomas Nilsen
14,957 Points

using Delegates in models to pass information between them

I want to make a HTTP request, and part of the request contains a lat and lng.

To get these I have a Location modal. One of it's delegate lets me know when it have a location ready. When that happens, I call my custom delegate which gets implemented in my Foursquare model.

I start everything in my MainViewController by creating an instance of the Location model and call startUpdatingLocation method. The implementation looks something like this:

Location model:

- (void)startLocationManager
{
    _locationManager = [[CLLocationManager alloc] init];
    _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
    _locationManager.delegate = self;

    [_locationManager startUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"Error:%@", error.userInfo);
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    if (locations) {
        _location = [locations lastObject];
        [self.delegate location:self didFinishFindingLocation:_location];
    }

}

Foursquare model:

- (void)location:(Location *)loc didFinishFindingLocation:(CLLocation *)location
{
    NSString *search = [NSString stringWithFormat:@"https://api.foursquare.com/v2/venues/search?ll=%f,%f&radius=2000&categoryId=4d4b7105d754a06374d81259&client_id=%@&client_secret=%@&v=%@", location.coordinate.latitude, location.coordinate.longitude, kFourdquareAPIKey, fFoursquareSecret, [Foursquare getCurrentDate]];

    NSURL *url = [NSURL URLWithString:search];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

    NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSDictionary *dataDictionary = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
        self.dataResponse = dataDictionary[@"response"][@"venues"];
        NSLog(@"%@", self.dataResponse);
    }];

    [task resume];
}

Lastly, I do this in my MainViewController:

Location *location = [[Location alloc] init];
[location startLocationManager];

Nothing is logged to the console, and the simulator doesn't ask me for permission to get locations. Nothing.

1) Is it wrong to use delegates like this? 2) Is there a better way?

Given that 1's answer is no, what's wrong with my code?

3 Answers

Thomas Nilsen
Thomas Nilsen
14,957 Points

Amit gave me the correct answer a couple of days ago in a related post. I'll paste his answer:

"You need to make location a property of your view controller instead of a local variable in the viewDidLoad. Otherwise it is created and deallocated within that method. You need it to live through the lifecycle of your view controller."

As soon as I did that it solved my problems.. ;)

Sabine Geithner
Sabine Geithner
3,264 Points

Did you tell your class that you are using the CLLocationDelegate protocol in your header? This goes behind the class name and superclass definition with <> brackets.

Otherwise use breakpoints to see if your application actually calls your methods. When the program stops at those breakpoints you can log your objects to the console egg. using "po locations" to see if your objects are not nil.

Thomas Nilsen
Thomas Nilsen
14,957 Points

Are you referring to my MainViewController where I call "[location startLocationManager];"? In which case is the answer no, but that shouldn't really be necessary? After all, I am importing "Location.h", and that does use the location delegate. But I'll try using breakpoints to see where it leads.

Thomas Nilsen
Thomas Nilsen
14,957 Points

I seems like

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations

never gets called.

- (void)startLocationManager

does get called however....I don't know what to make of this. After all it is a delegate method. Only thing I can think of is when I set the 'delegate = self' in the "- (void)startLocationManager". Self means the Location model. Should it be the viewController that actually calls it instead, or something like that?

Sabine Geithner
Sabine Geithner
3,264 Points

Hey, did you try adding the CLLocationManagerDelegate? You have to just add it in your interface after the class declaration. Should look something like this I guess

@interface MainViewController : UIViewController <CLLocationManagerDelegate>