2009-11-08 31 views
6

Objective-C使用動態綁定:即在運行時解析方法調用。動態綁定看起來像一個謊言

好。

而且use of dot notation really boils down to a method call

但是,爲什麼那麼,我不能做這樣的事情:

 
#import <Foundation/Foundation.h> 

int main (int argc, const char * argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 


    // Intercept the exception 
    @try 
    { 
    @throw [ NSException 
      exceptionWithName:@"Exception named ME!" 
      reason:@"Because i wanted to" 
      userInfo:nil ] ; 
    } 
    @catch(id exc) // pointer to an exception object? 
    { 



    //NSLog(@"%@ : %@\n", exc.name, exc.reason) ; // ILLEGAL: Request for member 
    // 'name' in something not a structure or union.. 
    // If objective-c uses dynamic binding, and dot notation 
    // boils down to calling the getter, then 
    // WHY do I have to cast to the concrete type here? 

    // Only works if I cast to the concrete type NSException* 
    NSException* nexc = (NSException*)exc ; 
    NSLog(@"%@ : %@\n", nexc.name, nexc.reason) ; 



    } 



    [pool drain]; 
    return 0; 
} 

當我聽到「動態綁定」我想「,所以應該像一個腳本語言「,,我很驚訝Objective-C與JavaScript等腳本語言相比的靈活性。

+2

你在混淆動態綁定與蛋糕。蛋糕是一個謊言。 – 2009-11-08 17:10:23

+1

_「方法調用在運行時被解析」_實際上應該被認爲是「在運行時發生的消息調度」_。整個_dot操作符的用法比其他任何操作都更具破壞性。 – 2009-11-08 17:31:29

+2

沒有什麼可以做的,它是具有一個附加約束的方法調用的非常明確的同義詞,該約束類型必須是衆所周知的。 (無論是否喜歡這個點或認爲這是一個很好的補充是完全的意見 - 沒有評論:)。 – bbum 2009-11-08 17:33:25

回答

17

令人困惑的是運行時和編譯器。運行時沒有問題應對。問題是點符號(這是句法糖)需要編譯器的類型信息來消除Objective-C對象和C結構之間的歧義。

如果不使用點標記它的工作原理:

NSLog(@"%@ : %@\n", [exc name], [exc reason]) ; 

如果類型不是ID,因爲編譯器知道它知道類型並不能保證調度的上面會生成一個警告將工作,但它會編譯和運行。

從根本上講,手頭的問題是編譯器需要知道是生成一個結構加載還是一個Objective C調度,換句話說,使用點符號它需要有足夠的信息來確定對象和標量類型。

0

Objective-C確實支持動態綁定。但是,您不能在'id'類型的對象上使用屬性 - 但是您可以向其發送任何您想要的消息。 (這可能是當前的定義/執行一個錯誤......但讓我們離開那個放在一邊。)

如果你沒有

NSLog(@"%@ : %@", [exc name], [exc reason]); 

然後它會工作。請注意,您不需要在NSLog語句中放置換行符,因爲它們都在單獨的行上。

+2

請確保您閱讀bbum的答案。實施不是一個錯誤,而是有目的的。 – danimal 2009-11-08 17:36:55

+0

夠公平的,必須在同一時間回答:-) – AlBlue 2009-11-09 10:02:08

17

動態綁定不同義爲動態分類。 C是一種強類型語言,特別是參數或返回值的類型非常重要,可以顯着影響代碼生成。

屬性專門設計用於消除歧義。作爲其中的一部分,決定對而不是允許針對id使用點語法。

具體來說,它解決了這樣的情況:

@interface Foo 
- (short) length; 
@end 

@interface Bar 
- (unsigned long long) length; 
@end 

鑑於兩個獨立的頭文件上面的[anObject length]編譯將給予警告只有兩個頭文件已導入。如果只導入了一個頭文件,那麼調用站點將被編譯,返回頭中看到的類型。如果呼叫站點用於其他方法,則會返回非常意外的結果。

對點語法的限制消除了這種潛在的不明確性。這也是你爲什麼不是一般會看到方法的共同變體聲明的原因。 C ABI只是不能很好地支持它(這就是說,Objective-C在支持對象類型協方差方面做得不好)。

實際上,Objective-C開發人員很少使用id類型。特定的類型聲明使編譯器能夠顯着改進其代碼驗證。

+0

像往常一樣優秀的答案,比爾!瞭解設計決策的細節總是很好的。我同意,我很謹慎地使用'id',因爲當我能夠得到它時,我經常更喜歡靜態打字的好處。 – 2009-11-10 04:06:49

相關問題