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