2013-02-26 88 views
3

在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 

为什么会出现这种情况?它是否正确?我没有收到任何错误或警告。协议方法声明中的 -/+是否执行某些操作?

+0

类方法的范围中没有自我。你可以引用一个单例。 – 2013-02-26 09:21:55

+5

@NickWeaver你可以在类方法中使用'self',它将指向'Class'对象为'[MyClass class]' – 2013-02-26 09:38:32

+0

@xlc我的不好,谢谢澄清。 – 2013-02-26 10:46:34

回答

1

首先,你必须知道一个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。

+0

请不要说“Class类对象”。它听起来像'Class'是一个类。 – newacct 2013-02-26 21:34:13

+0

@newacct不知道如何正确地说......任何建议? – 2013-02-26 22:26:22

+0

只是“类对象”(小写)我会觉得很好 – newacct 2013-02-26 22:59:04

-3

要设置self作为警报代表这是动态的 - 但方法调用是静态的,所以这是错误摆在首位,因为当你将调用+ (void)myStaticMethod一些时间在未来self可能是未初始化的并且nil。那为什么会出现其他错误以及未定义的行为

2

在类方法中self引用类对象。类对象是一个普通的objc对象(派生自NSObject),它将接收发送给类(类方法,带有“+”)的消息。

在你的情况下,你使用类对象作为UIAlertView的代理(因为UIAlertView的API没有明确需要静态类型为id<UIAlertViewDelegate>的对象)。现在,alert视图只是将它的委托消息发送给类对象,而这又是好的,因为您将它们实现为类方法。

+0

在UIAlertView的头部我看到有这样一行:@property(nonatomic,assign)id/* */delegate ;.该协议已被注释掉。为什么这不是id ?如果它不会被评论,我的代码仍然工作? – 2013-02-26 11:01:23

+0

“派生自NSObject”在技术上很好,派生自类的根类,在这种情况下,它是NSObject – newacct 2013-02-26 21:36:09

+0

@CristianIlea:1.我不知道他们为什么评论它。 2.如果没有注释掉,编译器可能会给你一个警告。 3.它在运行时是否工作取决于如何实现'UIAlertView'。如果它检查委托对象是否实际符合协议(使用'conformsToProtocol:'),它将不起作用。但是没有可可API曾经这样做过。如果它只是检查委托对选择器作出响应(使用'respondsToSelector:'),那么它将起作用。 – newacct 2013-02-26 21:41:42