Objective-c问题中的增强委托静态方法



我在objective-c中遇到了一个奇怪的问题。这是代码:

STViewController.h

#import <UIKit/UIKit.h>
@interface STViewController : UIViewController <UIAlertViewDelegate>
+(void)myStaticMethod;
@end

STViewController.m

#import "STViewController.h"
@implementation STViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    [STViewController myStaticMethod];
}
+ (void)myStaticMethod {
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Foo bar"
                                                    message:@"baz bat"
    //what does self even mean in this context? The class object STViewController?
                                                   delegate:self
                                          cancelButtonTitle:@"Cancel"
                                          otherButtonTitles:@"OK", nil];
    [alert show];
    [alert release];
}
#pragma mark UIAlertViewDelegate
// TRICKY PART if it's static it works, if it's not, it doesn't.
// even though the protocol declares instance methods (with a minus).
+ (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    NSLog(@"It works!");
}
@end

为什么会发生这种情况?这是正确的吗?我没有收到任何错误或警告。协议方法声明中的-/+有作用吗?

类内方法self指类对象。类对象是一个普通的objc对象(从NSObject派生(,它将接收发送到类的消息(类方法,带有"+"的方法(。

在您的案例中,您使用类对象作为UIAlertView的委托(这很有效,因为UIAlertView的API不明确要求静态类型为id<UIAlertViewDelegate>的对象(。现在,警报视图只会将其委托消息发送到类对象,这也很好,因为您将它们实现为类方法。

首先,您必须知道Class(通常来自[MyClass class](对象也是有效的ObjC对象。这意味着您也可以向类对象发送消息。

例如

@interface MyClass : NSObject
+ (NSString *)name;
@end
@implementation MyClass
+ (NSString *)name {
    return NSStringFromClass(self); // note in class method, self == [MyClass class]
}
@end
// ------- in some method
id cls = [MyClass class]; // the correct type should be Class, but since Class is an object, id will also work
NSLog(@"%@", [cls name]); // call like instance method - MyClass
NSLog(@"%@", [MyClass name]); // call like class method - MyClass

因此,您可以像使用其他对象一样使用类对象,并像调用实例方法一样调用类方法。

类方法实际上是实例方法!!不同之处在于类方法是元类的实例方法,后者是Class的类。有关元类的更多信息:http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html


此外,您的类接口是不正确的,因为不可能(至少在编译器时(向元类添加协议。因此,如果你这样做,[self conformsToProtocol:@protocol(UIAlertViewDelegate)]将返回NO。但你实现了+ alertView:clickedButtonAtIndex:,它将添加此方法作为元类的实例方法,因此委托代码有效,[self responseToSelector:@selector(alertView:clickedButtonAtIndex:)]将返回YES。

您将self设置为动态的警报委托,但方法调用是静态的,因此这是错误的,因为当您在未来某个时间调用+ (void)myStaticMethod时,self可能未初始化,而是nil。这就是为什么可能会出现其他错误以及未定义的行为

最新更新