Objective-C的Introspection(內省)

LeeJTom發表於2018-03-22

Introspection 官方文件

Introspection(內省)

  • 內省是面嚮物件語言和環境的一個強大功能,Objective-C和Cocoa的內省也不例外。
  • 內省是指物件在執行時將其自身細節洩露為物件的能力。 這些細節包括物件在繼承樹中的位置,它是否符合特定的協議,以及它是否響應某個特定的訊息。以及它是否響應某一訊息。

NSObject 協議和類定義了許多內省方法, 可用於查詢執行時以描述物件。

  1. class和superclass方法
  2. isKindOfClass:和isMemberOfClass:
  3. respondsToSelector:
  4. conformsToProtocol:
  5. isEqual:

評估繼承關係

  • 使用classsuperclass方法
// ...
while ( id anObject = [objectEnumerator nextObject] ) {
    if ( [self class] == [anObject superclass] ) {
        // do something appropriate...
    }
}
複製程式碼

注意:有時您使用classor superclass方法來獲取class訊息的適當接收者。

  • isKindOfClass:isMemberOfClass:

    • 相同點:都是NSObject中比較Class的方法。

    • 不同點:

      • isKindOfClass:

      用來判斷某個物件是否屬於 某個類,或者是屬於該類 繼承的任何類的例項類

      • isMemberOfClass:

      用來判斷某個物件是否為 指定類 的例項。 不能檢測任何的類都是基於NSObject類這一事實,而isKindOfClass可以。

首先建立個JTBody類基於NSObject,然後建立個JTFoot類基於JTBody類

- (void) test {
	JTFoot *foot = [[JTFoot alloc] init];
	if ([foot isKindOfClass:[JTBody class]]) {
		NSLog(@"foot isKindOfClass JTBody");
	}
	
	if ([foot isMemberOfClass:[JTFoot class]]) {
		NSLog(@"foot isMemberOfClass JTFoot");
	}
	
	if ([foot isMemberOfClass:[JTBody class]]) {
		NSLog(@"foot isMemberOfClass JTBody");
	}
}
複製程式碼

列印也驗證了上邊對兩者的論述:

IntroductionDemo[5380:2729984] foot isKindOfClass JTBody
IntroductionDemo[5380:2729984] foot isMemberOfClass JTFoot

方法的實現和協議一致性

  • respondsToSelector:

檢查一個物件是否實現了某種方法

  • conformsToProtocol:

檢查一個物件是否符合指定的形式協議 使用respondsToSelector:

 - (void)doCommandBySelector:(SEL)aSelector {
    if([selfrespondsToSelector:aSelector]){
        [self performSelector:aSelector withObject:nil];
    } else {
        [_client doCommandBySelector:aSelector];
    }
}
複製程式碼

使用conformsToProtocol:

// ...
if (!([((id)testObject) conformsToProtocol:@protocol(NSMenuItem)])) {
    NSLog(@"Custom MenuItem, '%@', not loaded; it must conform to the
        'NSMenuItem' protocol.\n", [testObject class]);
    [testObject release];
    testObject = nil;
}
複製程式碼

物件比較

  • isEqual:

雖然他們不是嚴格的內省方法,但是 hash 和 isEqual:方法履行類似的作用。它們是用於識別和比較物件的不可或缺的執行時工具。但不是查詢執行時獲取關於物件的資訊,而是依賴於特定於類的比較邏輯。

- (void)saveDefaults {
    NSDictionary *prefs = [self preferences];
    if (![origValues isEqual:prefs])
        [Preferences savePreferencesToDefaults:prefs];
}
複製程式碼

如果您正在建立一個子類,您可能需要重寫isEqual:以新增對相等點的進一步檢查。子類可能會定義一個額外的屬性,在兩個例項中它們必須是相同的值才能被視為相等。例如,假設你建立一個包含兩個例項變數name 與data的NSObject子類MyWidget。這兩者必須是兩個相同的值MyWidget才能被視為相等。

重寫isEqual:

- (BOOL)isEqual:(id)other {
   if (other == self)
       return YES;
   if (!other || ![other isKindOfClass:[self class]])
       return NO;
   return [self isEqualToWidget:other];
}

- (BOOL)isEqualToWidget:(MyWidget *)aWidget {
   if (self == aWidget)
       return YES;
   if (![(id)[self name] isEqual:[aWidget name]])
       return NO;
   if (![[self data] isEqualToData:[aWidget data]])
       return NO;
   return YES;
}
複製程式碼

isEqual:方法首先檢查指標是否相等,然後檢查類是否相等,最後呼叫一個物件比較器,其名稱指示比較中涉及的物件類。這種比較器強制傳入物件的型別檢查,這在Cocoa中是一個常見的約定; 類的 isEqualToString:方法和NSString類的isEqualToTimeZone:方法NSTimeZone只是兩個例子。類特定的比較器- isEqualToWidget:在這種情況下 - 執行名稱和資料相等性的檢查。

在Cocoa框架的所有isEqualToType:方法中,nil不是一個有效的引數,並且這些方法的實現可能會在接收到一個異常時引發異常nil。但是,為了向後相容,isEqual: Cocoa框架的方法確實接受nil並返回NO。

相關文章