iOS學習筆記7 - 前置聲明(Forward Declaration),@class與#import


C#寫多了都忘記有前置聲明(Forward Declaration)這么回事了,看到@class的時候楞了半天。今天就寫這個主題吧。

 

1. 為什么需要前置聲明

前置聲明有助於避免循環依賴。像:

interface A:NSObject
- (B*)calculateMyBNess;
@end

@interface B:NSObject
- (A*)calculateMyANess; 
@end

 

這樣聲明無法編譯,因為會遇到先有雞還是先有蛋的問題。

這時候就需要加一個前置聲明:

@class B;
@interface A:NSObject
- (B*)calculateMyBNess;
@end

@interface B:NSObject
- (A*)calculateMyANess; 
@end

@class告知編譯器,在某個地方有叫這樣名字的一個類存在。

  

2. @class vs. #import

從語法上,使用前置聲明和使用#import都能編譯通過與運行成功。

那么,這兩者分別適用什么場合?

根據http://stackoverflow.com/questions/322597/class-vs-import, 

如果你看到警告: 

warning: receiver 'myCoolClass' is a forward class and corresponding @interface may not exist

就需要import這個文件了。不過可以不是直接在.h(頭文件)里import,而是在.m(implementation文件)里import,在頭文件里使用@class聲明。

 

@class通常可以使你不用過早地import。如果編譯器看到了一行語法:

@class myCoolClass,它就知道了自己可能馬上會看到類似如下的代碼:

myCoolClass *myObject;

於是它會為這個類保留一個指針的空間,然后忙其他的去了。

不過如果你需要創建或訪問myObject的成員,那么僅僅一個類指針就不夠了。你需要讓編譯器知道這些成員到底是什么。這時候就需要#import "myCoolClass.h"了。

 

有人簡單列了三條規則。由於水平不夠,翻譯的話可能會導致歧義,我直接放原文:

  • Only #import the super class, and adopted protocols, in header files.
  • #import all classes, and protocols, you send messages to in implementation.
  • Forward declarations for everything else. 

http://stackoverflow.com/questions/6076207/objective-c-forward-declarations-vs-imports

有人提到過,根據他的經驗,用#import不慎,有可能會讓編譯器多編譯N多代碼(他用了million這個數量級)。只要有一個頭文件被稍微修改,所有import的類都需要重新編譯,於是拖長了編譯時間。

 

3. 為什么C#不需要前置聲明?

我個人Google了一下,沒有找到相關的解釋。看起來幾乎沒人對C#為什么沒有前置聲明感興趣。。。

關於這個問題我和朋友Zero討論了一下,他的意見如下:

“C# compiler能夠多遍掃描源代碼所以不需要任何前置聲明。理論上C++ compiler也可以,不過事實上C++ compiler沒有這么做而已。”

 

當然C#也會有循環依賴。這種時候可以用依賴注入(控制反轉)來消除,具體可以參見如下:

http://stackoverflow.com/questions/3955465/circular-class-reference-problem


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM