在Objective-c问题中访问委托静态方法

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

STViewController.h

#import  @interface STViewController : UIViewController  +(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 

为什么会这样? 它是否正确? 我没有收到任何错误或警告。 协议方法声明中的 – / +是否有效?

首先,您必须知道一个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指的是类对象。 类对象是一个普通的objc对象(派生自NSObject ),它将接收发送给类的消息(类方法,带有“+”的方法)。

在您的情况下,您使用类对象作为UIAlertView的委托(这是因为UIAlertView的API没有明确要求静态类型id的对象)。 现在,警报视图只是将它的委托消息发送到类对象,这也很好,因为您将它们实现为类方法。

你将self设置为动态的警报委托 – 但是方法调用是静态的,因此首先是错误的,因为当你将调用+ (void)myStaticMethod未来的某个时候, self可能是未初始化的并且是nil 。 这就是为什么其他错误可能会跟随未定义的行为