聲明:此文章是做個人筆記查閱用的,不是供他人來抨擊抄襲的!!!
與C、C++一樣,Objective-C也使用“頭文件”和“實現文件”來區隔代碼。用Objective-C語言編寫類的標準方式:以類名做文件名,分別創建2個文件,頭文件后綴.h,實現文件.m
用Objective-C語言編寫任何類幾乎都需要引入Foundation.h,如果不在該類本身引入這個文件的話,那么就要引入與其超類所屬框架相對應的"基本頭文件".
比如編寫了一個CWGPerson的類,過了一段時間有創建了一個CWGEmployer的新類,然后每個CWGPerson實例都應該有一個CWGEmployer.于是我們一般會這樣寫:
#import "CWGEmployer.h"
@interfance CWGPerson : NSObject
@property (nonatomic, strong) CWGEmployer *employer;
@end
這樣做不是不行,只是不夠優雅罷了.因為在編譯一個使用了CWGPerson類的文件時,不需要知道CWGEmployer類的全部細節,只需要知道有一個類名CWGEmployer就可以了.于是我們還可以這樣寫:
@class CWGEmployer
@interfance CWGPerson : NSObject
@property (nonatomic, strong) CWGEmployer *employer;
@end
CWGPerson類的實現文件,也就是CWGPerson.m文件則需要引入CWGEmployer類的頭文件,因為要使用后者,則必須知道期所有的接口細節.
#import "CWGPerson.h"
#import "CWGEmployer.h"
@implementation CWGPerson
// Implementation of methods
@end
將引入頭文件的時機盡量延后, 只在確有需要時才真正引入,這樣可以減少類的使用者所需引入頭文件的數量.假如把CWGEmployer.h引入到CWGPerson.h中,那么只要引入CWGPerson.h,就會引入CWGEmployer.h的全部內容.如此持續下去,則要引入很多根本用不到的內容,還增加了編譯時間.
向前聲明還避免了兩個類相互引用的問題,例如CWGEmployer.m中增加了方法:
- (void)addEmployee:(CWGPerson *)person;
這時候編譯CWGEmployer,編譯器必須知道CWGPerson這個類,而要編譯CWGPerson,又必須知道CWGEmployer.這時候就會導致"循環引用".雖然使用#import不會導致死循環(#include會),但是這意味著2個類有一個是無法編譯成功的,如果不信,讀者可以嘗試下.
還有一點需要注意,那就是有時候必須要在頭文件中引入其他頭文件,如果你寫的類繼承某個超類,則必須引入定義那個超類的頭文件.同理,如果要聲明你寫的那個類遵從某個協議(protocol),那么該協議必須有完整的定義.且不能使用"向前聲明".因為"向前聲明"只能告訴編譯器有這么個協議,但是編譯器這時要知道這個協議中定義的方法.例如:
#import "CWGShape.h"
#import "CWGDrawable.h"
@interface CWGRectangle : CWGShape <CWGDrawable>
@property (nonatomic, assign) CGFloat width; ///< 寬
@property (nonatomic, assign) CGFloat height; ///< 高
@end
其中#import "CWGDrawable.h"是難免的.對于這種情況,最好是把協議單獨放在一個頭文件里.但是把CWGDrawable協議放在某個打的頭文件里,那么只要引入此協議,必定會引入頭文件中的全部內容,如此一來又會出現上面講的問題.
然而對于委托協議,就不用單獨寫到一個頭文件里了.這種情況下,協議只有和接受協議的類放在一起才有意義.此時最好能在實現文件(.m文件)中聲明此類實現了該委托協議.并把這段代碼放在"class - continuation 分類"里.這樣的話, 只要在實現文件中引入包含委托協議的頭文件即可,而不需要將其放在公共頭文件里.
每次在頭文件張引入其他頭文件之前,都問問自己這樣做是否真的有必要.如果可以使用"向前聲明"取代引入,那么就不要引入.若因為要實現屬性, 實例變量或要遵循協議必須引入頭文件,則應盡量移至到class - continuation 分類中.這樣做不僅能縮減編譯時間,而且能降低彼此的依賴性.如果依賴過于復雜,則會給維護帶來麻煩.而且如果只想把代碼的某個部分開放為公共的API,太過復雜的依賴關系也會出問題.
總結
除非確有必要,否則不要引入頭文件.一般說來,應該在某個類的頭文件中使用"向前聲明"來提及別的類.并在實現文件中引入那些類的頭文件,這樣做可以盡量降低類之間的耦合性.
有時無法使用"向前聲明",比如某個類要遵從某個協議,這種情況下,盡量把"該類遵循某協議"的聲明移至到"延展"中(class - continuation 分類).如果還不行,就把協議單獨放在一個頭文件中,然后將其引入.