【问题标题】:Using a class (not an instance) as an iOS delegate, CLLocationManager delegate callbacks aren't called使用类(不是实例)作为 iOS 委托,不会调用 CLLocationManager 委托回调
【发布时间】:2015-02-01 16:41:11
【问题描述】:

相关: Can I use a class method as a delegate callback?

我正在尝试使用静态类 MyClass 作为其自己的静态 CLLocationManager 成员的委托,但我实现的 CLLocationManager 委托方法没有被调用。我已将委托设置为[myClass class],正确实现了委托方法,并将协议包含在 MyClass.h 中。

MyClass.h

@interface iOSSonic : NSObject <CLLocationManagerDelegate>

MyClass.m

locationManager 声明:

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

我正在通过以下方法懒惰地实例化静态 CLLocationManager:

+(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;
}

...然后从我的 ViewController 调用以下 MyClass 方法:

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

委托方法实现:

...
+(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 

为了确保这不是与让委托是静态(不可实例化)类和委托回调是类方法相关的问题,我还尝试将 locationManager 作为@property 而不是静态成员,并且创建了一个 myClass 的实例,将 myClass 的 locationManager 的委托设置为 self。我还将getLocationManager 替换为覆盖的locationManager getter,并将委托回调更改为实例方法。

MyClass.m

初始化:

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

LocationManager 声明和实例化:

...
@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;
}

委托方法实现:

...
-(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];

我做错了什么?

【问题讨论】:

    标签: ios objective-c delegates static-methods static-members


    【解决方案1】:

    这是一个愚蠢的位置服务权限问题。原来它与静态成员、类与实例等无关。这为我解决了这个问题:https://stackoverflow.com/a/25765345/1402368

    当然是这样的蠢事……

    【讨论】:

      【解决方案2】:

      这是我对正在发生的事情的理解:

      Objective-C 中实例方法调用和类方法调用在语义上是不同的,不能互换。

      方法声明:

      +(void)someMethod;
      

      -(void)someMethod;
      

      定义 2 种不同的方法。要调用它们,您必须知道您是在调用实例方法还是类方法,并相应地进行编码。

      位置管理器被编写为在其委托上调用 INSTANCE 方法,而不是类方法。

      因此,你不能做你想做的事(让 CLASS 成为委托而不是类的实例。)

      您也许可以设计自己的自定义类,其对象希望将一个类设置为它们的委托,但是您只能将一个类指定为委托,而不是该类的实例。

      【讨论】:

      • 虽然在文档中,委托方法被声明为实例方法,但至少根据this SO post 将委托方法实现为类方法是完全可以的。
      • 另一个问题是 CLLocationManager 实例是否将接受一个类而不是实例作为其委托。然而,正如我解释的那样,我通过将 MyClass 重新实现为可实例化类而不是静态类来测试这一点,并将旧的静态 MyClass 替换为新 MyClass 的实例作为 locationManager 的委托,但仍然存在相同的问题(委托方法--现在实例方法--仍然没有被调用)。
      • 不,这没有意义。消息分派没有做出这种区分。如果您有id,您可以发送类或实例消息,相应的方法将运行。
      • 乔希,你说“适当的方法会运行”。是的,如果你向一个 ID 发送一个类消息,它会尝试调用一个类方法,如果你发送一个实例消息,它会尝试运行一个实例方法。这正是我的观点。位置管理器明确希望将实例消息发送到委托的实例方法。如果您只有一个类方法,则没有实例方法,因此您的对象不会响应消息并且它会掉在地板上。
      • 不,因为您没有发送“实例消息”。没有这样的事情。您只是发送 a 消息,而对象(类对象或实例)会弄清楚如何处理它。如果对象没有响应,它将引发异常。请参阅我提出的要点。
      猜你喜欢
      • 1970-01-01
      • 2014-09-20
      • 1970-01-01
      • 2016-05-07
      • 1970-01-01
      • 1970-01-01
      • 2011-03-12
      • 2011-11-29
      • 1970-01-01
      相关资源
      最近更新 更多