orangebanana3
orangebanana3

Reputation: 538

Using a class (not an instance) as an iOS delegate, CLLocationManager delegate callbacks aren't called

Related: Can I use a class method as a delegate callback?

I'm trying to use a static class, MyClass, as a delegate for its own static CLLocationManager member, but the CLLocationManager delegate methods I've implemented aren't being called. I've set the delegate as [myClass class], properly implemented the delegate methods, and included the protocol in MyClass.h.

MyClass.h

@interface iOSSonic : NSObject <CLLocationManagerDelegate>

MyClass.m

locationManager declaration:

@implementation myClasss : NSObject
...
static CLLocationManager *locationManager = nil;

I'm lazily instantiating the static CLLocationManager via the follow method:

+(CLLocationManager*)getLocationManager {
    if (locationManager == nil) {
        locationManager = [[CLLocationManager alloc] init];
        locationManager.delegate = [myClass class]; // we set the delegate of locationManager to self.
        locationManager.desiredAccuracy = kCLLocationAccuracyBest; // setting the accuracy
        locationManager.distanceFilter = 0.5; // get updates for location changes > 0.5 m
        [locationManager requestWhenInUseAuthorization];
    }
    return locationManager;
}

...and then from my ViewController calling the following MyClass method:

+(void)myFunction {
    [self.getLocationManager startUpdatingLocation];
}

Delegate method implementations:

...
+(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
...
}

+(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
...

}

ViewController.m

// no initialization needed for static myClass

- (IBAction)onButtonClick:(id)sender {
    [myClass myFunc] // This should trigger the didUpdateLocations delegate method, but it doesn't 

To ensure that this wasn't some problem related to having the delegate be a static (non-instantiable) class and the delegate callbacks be class methods, I also tried with locationManager as a @property rather than a static member, and created an instance of myClass, setting myClass's locationManager's delegate to self. I also replaced getLocationManager with an overridden locationManager getter, and changed the delegate callbacks to instance methods.

MyClass.m

Initialization:

-(id)init {
    if (self = [super init]) {
        // do nothing
    }
    return self;
}

LocationManager declaration and instantiation:

...
@interface MyClass()
@property (strong, nonatomic) CLLocationManager *locationManager;
@end
@implementation
...

// Lazily instantiate locationManager
-(CLLocationManager*)locationManager {
    if (!_locationManager) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self; // we set the delegate of locationManager to self.
        _locationManager.desiredAccuracy = kCLLocationAccuracyBest; // setting the accuracy
        _locationManager.distanceFilter = 0.5; // get updates for location changes > 0.5 m
        [_locationManager requestWhenInUseAuthorization];
    }
    return _locationManager;
}

Delegate method implementations:

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

-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
...

}

ViewContoller.h

...
@property (strong, nonatomic) myClass *myClassInstance;
...

ViewController.m

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        ...
        self.myClassInstance = [[myClass alloc] init];

What am I doing wrong?

Upvotes: 0

Views: 1022

Answers (2)

orangebanana3
orangebanana3

Reputation: 538

It was a stupid location services permissions thing. Turns out it had nothing to do with static members, classes vs. instances, etc. This fixed it for me: https://stackoverflow.com/a/25765345/1402368

Of course it was something stupid like this...

Upvotes: 0

Duncan C
Duncan C

Reputation: 131418

Here's my understanding of what's going on:

Instance method calls and class method calls are semantically different in Objective-C, and not interchangeable.

The method declarations:

+(void)someMethod;

and

-(void)someMethod;

Define 2 different kinds of methods. To call them, you have to know if you're calling an instance method or a class method, and code accordingly.

The location manager is written to call INSTANCE methods on it's delegate, not class methods.

Thus, you can't do what you're trying to do (make a CLASS a delegate instead of an instance of a class.)

You might be able to design your own custom class who's objects expect to have a class set as their delegate, but then you would only ever be able to assign a class as the delegate, never an instance of that class.

Upvotes: -1

Related Questions