2013-02-26 66 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