簡體   English   中英

為什么可以在類名或類對象上使用-respondsToSelector:實例方法?

[英]Why can -respondsToSelector: instance method be used on class name or class object?

在Objective C的編程,4e,第9章,程序9.3中:

#import "Square.h"
int main (int argc, char * argv[])
{
   @autoreleasepool {
      Square *mySquare = [[Square alloc] init];
      ...
      // respondsTo:
      if ( [mySquare respondsToSelector: @selector (setSide:)] == YES )
         NSLog (@"mySquare responds to setSide: method");
      ...
      if ( [Square respondsToSelector: @selector (alloc)] == YES )
         NSLog (@"Square class responds to alloc method");
      ...
   }
   return 0;
}

Q1:

由於-respondsToSelector:是實例方法,而不是類方法,為什么可以直接在Square類上使用它?

Q2:

該書說您可以在此處使用Square而不是[Square class] 它只是一個特殊的捷徑,還是背后有任何機制?

任何幫助將非常感激! 提前致謝!

Q1:

簡單的答案是,除了類方法之外,您還可以在類對象上調用根類的任何實例方法(無論您的類的根類是什么;在本例中為NSObject )。

更為復雜的答案是,類對象是元類的實例。 實例方法是實例上在類中定義的方法; 類方法是類對象上的方法,這些方法在元類中定義。 每個類都有其自己的元類。 元類的繼承遵循其類的繼承。 NSString的元類繼承自NSObject的元類。 最終,根類的元類繼承自根類。 NSObject的元類繼承自NSObject 這就是為什么所有NSObject的實例方法都可用於類對象的原因。

Q2:

[Square class]調用類方法+class (這與-class無關)。 +class本質上是一個標識方法,它僅返回調用它的東西(就像-self一樣); 也就是說,如果foo是指向類對象的指針,則[foo class]foo相同。

所以+class似乎毫無用處; 我們為什么用它? 這是因為在Objective-C語言的語法中,類名不是有效的表達式(與Smalltalk不同)。 因此,您不能說id bar = Square; ; 那不會編譯。 作為語法的一種特殊情況,在消息調用表達式中允許使用類名代替接收者,並將消息發送到類對象。 [Square something] 因此,如果您想在任何其他表達式上下文中使用class對象,我們可以通過調用+class的標識方法,以一種繞行方式進行操作 [Square class]是可以在任何表達式上下文中使用的表達式( [Square self]也可以使用,但是我們習慣上使用[Square class] ,這很不幸,因為它與-class混淆了); 我們本來希望只使用Square ,但由於語言原因而不能。

在您的情況下,它已經是消息調用表達式中的接收者,因此不必執行[Square class] Square已經在那里工作了。

Objective-C編程語言對象,類和消息傳遞中

所有對象,類和實例都需要與運行時系統的接口。 類對象和實例都應該能夠對它們的功能進行自省,並能夠報告它們在繼承層次結構中的位置。 提供此接口是NSObject類的省。

這樣一來,不必執行兩次NSObject方法(一次為實例提供運行時接口,再為類對象復制該接口),就可以對類對象進行特殊分配以執行根類中定義的實例方法 當類對象收到無法使用類方法響應的消息時,運行時系統將確定是否存在可以響應的根實例方法。 類對象可以執行的唯一實例方法是在根類中定義的實例方法,並且僅當沒有類方法可以執行此工作時才可以執行

在這種情況下, NSObject是根類。 由於NSObject實例均符合定義了-respondsToSelector: NSObject protocol ,因此大多數類對象應能夠執行-respondsToSelector:

// Q1:

由於-respondsToSelector:是實例方法,而不是類方法,為什么可以直接在Square類上使用它?//

您似乎有一個想法,即不能從實例方法中調用類方法(反之亦然)。 相反,這似乎是方法-respondsToSelector的意圖,很可能是通過使用-class方法獲取發送方的類,然后查詢該類是否對選擇器作出響應並返回YES或NO。 在一個更加本地化的示例中,請考慮以下內容:

-(void)someInstanceMethod{
     [MyCurrentClass doClassMethod]; //basic equivalent of [self doClassMethid];
}

如果MyCurrentClass全部分配和初始化,則在Objective-C中完全有效。

//第二季度:

這本書說您可以在這里使用Square而不是[Square class]。 它只是一個特殊的捷徑,還是背后有任何機制?//

將-class發送到Class完全是多余的! 這沒有什么意義,只是多余的代碼。 -class只是查詢接收者的類,無論它是實例還是Class對象。

當前,Objective C運行時將一個類實現為某個其他類的實例對象。 因此,一個類將響應某些實例方法。

真正的實現,直接來自NSObject.m,是這樣的:

- (BOOL)respondsToSelector:(SEL)aSelector {
        PF_HELLO("")
        return class_respondsToSelector( isa, aSelector );
}

現在,我不知道為什么有PF_HELLO("") ,但是正如您所看到的,它實際上是在運行時PF_HELLO("") CLASS“嘿,您是否有一個用於此isa的方法,稱為aSelector?”

並且,在Objective-C中,類方法ALSO屬於實例,但是優先級較低(與類方法同名的實例方法在類方法之前被調用)。

Objective-C動態鍵入的另一個方面是, id類型實際上聲明如下:

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id;

因此,您的實例對象實際上是一個Class指針。 這意味着您的-respondsToSelector消息也將轉到實例類型的Class。 在您的情況下,這意味着-respondsToSelector將轉到objc_class FIRST。

現在在一個測試案例中(直接來自libFoundation),我的答案將像這樣總結:

Test *tst = [Test new];

    fail_unless([tst respondsToSelector:@selector(testInstanceMethod)], "-[Test respondsToSelector:] returned NO for a valid instance method (testInstanceMethod).");
    fail_if([tst respondsToSelector:@selector(testClassMethod)], "-[Test respondsToSelector:] returned YES for a class method (testInstanceMethod).");
    fail_unless([Test respondsToSelector:@selector(testClassMethod)], "+[Test respondsToSelector:] returned NO for a valid class method (testClassMethod).");
    fail_if([Test respondsToSelector:@selector(testInstanceMethod)], "+[Test respondsToSelector:] returned YES for an instance method (testInstanceMethod).");
    fail_unless([tst respondsToSelector:@selector(init)], "-[Test respondsToSelector:] returned NO for an inherited instance method (-[NSObject init].");
    fail_unless([Test respondsToSelector:@selector(alloc)], "+[Test respondsToSelector:] returned NO for an inherited class method (+[NSObject alloc]).");

    [tst release];

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM