本篇是我閱讀《Effective Objective-C 2.0 編寫高質(zhì)量iOS與OS X代碼的52個有效方法》的摘要與總結(jié)愿险。
一橱野、熟悉Objective-C
1.了解Objective-C語言的起源
Objective-C為C語言添加了面向?qū)ο筇匦阅耄瞧涑bjective-C使用動態(tài)綁定的消息結(jié)構(gòu)谷扣,也就是說竿开,在運行時才會檢查對象類型。接收一條消息之后掸读,究竟應(yīng)執(zhí)行何種代碼串远,由運行環(huán)境而非編譯器來決定宏多。
理解C語言的核心概念有助于寫好Objective-C程序。尤其要掌握內(nèi)存模型與指針澡罚。
CoreGraphics 中的CGRect 屬于結(jié)構(gòu)體伸但,如果用OC對象,性能會受影響
2.在類的頭文件中盡量少引入其他頭文件
除非確有必要留搔,否則不要引入頭文件更胖。一般來說,應(yīng)在某個類的頭文件中使用向前聲明(forward declaring)來提及別的類隔显,并在實現(xiàn)文件中引入那些類的頭文件却妨。這樣做可以盡量降低類之間的耦合。
有時無法使用向前聲明括眠,比如要聲明某個類遵循一項協(xié)議彪标。這種情況下,盡量把“該類遵循某協(xié)議”的這條聲明移至“class-continuation”分類中掷豺。如果不行的話捞烟,就把協(xié)議單獨放在一個頭文件中,然后將其引入当船。
頭文件中若想導(dǎo)入其他的類题画,用@class
3.多用字面量語法,少用與之等價的方法
應(yīng)該使用literal語法來創(chuàng)建字符串德频,數(shù)值苍息,數(shù)組,字典抱婉。與創(chuàng)建此類對象的常規(guī)方法相比档叔,這么做更加簡明扼要。
應(yīng)該通過取下標(biāo)操作來訪問數(shù)組下標(biāo)或字典中的鍵所對應(yīng)的元素蒸绩。
用literal語法創(chuàng)建數(shù)組或字典時衙四,若值中有nil,則會拋出異常患亿。因此传蹈,務(wù)必確保值里不含nil。
比如多用NSArray *array = @[@1,@2];少用NSArray *array = [NSArray arrayWithObjects:@1,@2,nil];
一句話步藕,就是代碼能寫簡單就寫簡單
4.多用類型常量惦界,少用#define預(yù)處理指令
不要用預(yù)處理指令定義常量。這樣定義出來的常量不含類型信息咙冗,編譯器只是會在編譯前據(jù)此執(zhí)行查找與替換操作沾歪。即使有人重新定義了常量值,編譯器也不會產(chǎn)生警告信息雾消,這將導(dǎo)致應(yīng)用程序中的常量值不一致灾搏。
在實現(xiàn)文件中使用static const來定義只在編譯單元內(nèi)可見的常量挫望。由于此類常量不在全局符號表中,所以無需為其名稱加前綴狂窑。
在頭文件中使用extern來聲明全局常量媳板,并在相關(guān)實現(xiàn)文件中定義其值。這種常量要出現(xiàn)在全局符號表中泉哈,所以其名稱要加以區(qū)隔蛉幸,通常用與之相關(guān)的類名做前綴。
用法:將#define EOCAnimatedViewAnimationDuration 0.3 替換為以下
EOCAnimatedView.h
extern const NSTime IntervalEOCAnimatedViewAnimationDuration;
EOCAnimatedView.m
const NSTime IntervalEOCAnimatedViewAnimationDuration = 0.3;
注意命名
5.用枚舉表示狀態(tài)丛晦、選項奕纫、狀態(tài)碼
應(yīng)該用枚舉來表示狀態(tài)機的狀態(tài)、傳遞給方法的選項遺跡狀態(tài)碼等值采呐,給這些值起個易懂的名字若锁。
如果把傳遞給某個方法的選項表示為枚舉型搁骑,而多個選項又可同時使用斧吐,那么就將各選項值定義為2的冪,以便通過按位或者操作將其組合起來仲器。
用NS_ENUM與NS_OPTIONS宏來定義枚舉類型煤率,并指明其底層數(shù)據(jù)類型。這樣做可以確保枚舉是用開發(fā)者所選的底層數(shù)據(jù)類型實現(xiàn)出來的乏冀,而不會采用編譯器所選的類型蝶糯。
在處理枚舉類型的switch語句中不要實現(xiàn)default分支。這樣的話辆沦,加入新枚舉之后昼捍,編譯器就會提示開發(fā)者:switch語句并未處理所有的枚舉。
用法:
typedef NS_Enum(NSUInteger,EOCConnectionState){
EOCConnectionStateDisconnected,
EOCConnectionStateConnecting,
EOCConnectionStateConnected,
}
switch(_currentState){
EOCConnectionStateDisconnected:
//Handle disconnected state
break;
EOCConnectionStateConnecting:
//Handle disconnected state
break;
EOCConnectionStateConnected:
//Handle disconnected state
break;
}
1 << 2 = 0b100
0b1111 >> 3 = 0b0001
二肢扯、對象妒茬、消息、runtime
6.理解“屬性”這一概念
可以通過@property語法來定義對象中所封裝的數(shù)據(jù)蔚晨。
通過“特質(zhì)”來指定存儲數(shù)據(jù)所需的正確語義
在設(shè)置屬性所對應(yīng)的實例變量時乍钻,一定要遵從該屬性所聲明的語義。
開發(fā)iOS程序時铭腕,應(yīng)該使用nonatomic屬性银择,因為atomic屬性會嚴重影響性能。
7.在對象內(nèi)部盡量直接訪問實例變量
由于不經(jīng)過Objective-C 的“方法派發(fā)”(method dispatch,見11)步驟础拨,所以直接訪問實例變量的速度當(dāng)然比較快呆抑。在這種情況下捌袜,編譯器所生成的代碼會直接訪問保存對象實例變量的那塊內(nèi)存。
直接訪問實例變量時析孽,不會調(diào)用其“設(shè)置方法”析蝴,這就繞過了為相關(guān)屬性所定義的“內(nèi)存管理語義”。比方說绿淋,如果在ARC下直接訪問一個聲明為copy的屬性闷畸,那么并不會拷貝該屬性,只會保留新值并釋放舊值吞滞。
如果直接訪問實例變量佑菩,那么不回觸發(fā)“鍵值觀察(Key-Value Observing, KVO)”通知裁赠。這樣做是否會產(chǎn)生問題殿漠,還取決于具體的對象行為。
通過屬性來訪問有助于排查與之相關(guān)的錯誤佩捞,因為可以給“獲取方法”和/或“設(shè)置方法”中新增“斷點(breakpoint)”監(jiān)測該屬性的調(diào)用者及其訪問時機
在對象內(nèi)部讀取數(shù)據(jù)時绞幌,應(yīng)該直接通過實例變量來讀,而寫入數(shù)據(jù)時一忱,應(yīng)該通過屬性來寫莲蜘。
在初始化方法及dealloc方法中,總是應(yīng)該直接通過實例變量來讀寫數(shù)據(jù)帘营。
有時會使用惰性初始化技術(shù)配置某份數(shù)據(jù)票渠,這種情況下,需要通過屬性來讀取數(shù)據(jù)芬迄。
8.理解“對象等同性”這一概念
若想檢測對象的等同性问顷,請?zhí)峁癷sEqual:”與hash方法。
相同的對象必須具有相同的hash碼禀梳,但是兩個hash碼相同的對象卻未必相同杜窄。
不要盲目的逐個監(jiān)測每條屬性,而是應(yīng)該依照具體需求來制定檢測方案算途。
編寫hash方法時塞耕,應(yīng)該使用計算速度快而且哈希碼碰撞幾率低的算法。
對象是否相同 不能用== 要用isEqual
NSString*foo =@"badger 123";
NSString*bar = [NSStringstringWithFormat:@"badger %i",123];
BOOLequalA = (foo == bar );//< equalA = NO
BOOLequalB = [fooisEqual:bar];//< equalB = YES
BOOLequalC = [fooisEqualToString:bar];//< equalC = YES
9.以“類族模式”隱藏實現(xiàn)細節(jié)
子類應(yīng)該繼承自類族中的抽象基類郊艘。
子類應(yīng)該定義自己的數(shù)據(jù)存儲方式荷科。
子類應(yīng)當(dāng)復(fù)寫超類文檔中指明需要復(fù)寫的方法
類族模式可以把實現(xiàn)細節(jié)隱藏在一套簡單的公共接口后面。
系統(tǒng)框架中經(jīng)常使用類族纱注。
從類族的公共抽象基類中繼承子類時要當(dāng)心畏浆,若有開發(fā)文檔,則應(yīng)首先閱讀狞贱。
例如NSArray與NSMutableArray
//? YDEmployee.h
#import
typedefNS_ENUM(NSUInteger, YDEmployeeType){
YDEmployeeTypeDeveloper,
YDEmployeeTypeDesigner,
YDEmployeeTypeFinance,
};
@interfaceYDEmployee :NSObject
@property(nonatomic, copy)NSString*name;
@property(nonatomic, assign)NSUIntegersalary;
//1.定義類方法刻获,根據(jù)不同type,放回同一父類對象
+(YDEmployee*)employeeWithType:(YDEmployeeType)type;
-(void)doWork;
@end
//? YDEmployee.m
#import"YDEmployee.h"
//3.定義各自子類
@interfaceYDEmployeeDeveloper :YDEmployee
@end
@implementationYDEmployeeDeveloper
-(void)doWork
{
[selfwriteCode];
}
-(void)writeCode
{
/////
}
@end
@interfaceYDEmployeeDesigner :YDEmployee
@end
@implementationYDEmployeeDesigner
-(void)doWork
{
[selfdesighApp];
}
-(void)desighApp
{
/////
}
@end
@interfaceYDEmployeeFinance :YDEmployee
@end
@implementationYDEmployeeFinance
-(void)doWork
{
[selfmanageFinance];
}
-(void)manageFinance
{
////
}
@end
@implementationYDEmployee
//2.抽象基類沒有特殊標(biāo)識瞎嬉,一般不定義init方法也不實現(xiàn)抽象函數(shù)蝎毡,各自在子類里實現(xiàn)
+(YDEmployee*)employeeWithType:(YDEmployeeType)type
{
switch(type) {
caseYDEmployeeTypeDeveloper:
return[YDEmployeeDevelopernew];
break;
caseYDEmployeeTypeDesigner:
return[YDEmployeeDesignernew];
break;
caseYDEmployeeTypeFinance:
return[YDEmployeeFinancenew];
break;
default:
break;
}
returnnil;
}
-(void)doWork
{
//2.1拋出一個異常厚柳,避免在基類里面實現(xiàn)
NSException*e = [NSException
exceptionWithName:@"exceptionName"
reason:@"必須在子類實現(xiàn)改方法"
userInfo:nil];
@throwe;
}
@end
10.在既有類中,使用關(guān)聯(lián)對象(Associated Object)存放自定義數(shù)據(jù)
可以通過“關(guān)聯(lián)對象”機制來把兩個對象連起來沐兵。
定義關(guān)聯(lián)對象時可指定內(nèi)存管理語義别垮,用以模仿定義屬性時所采用的“擁有關(guān)系”與“非擁有關(guān)系”。
只有在其他做法不可行時才應(yīng)選用關(guān)聯(lián)對象扎谎,因為這種做法通常會引入難于查找的bug碳想。
下列方法可以管理關(guān)聯(lián)對象:
voidobjc_setAssociatedObject(idobject,void*key,idvalue, objc_AssociationPolicy policy)此方法以給定的鍵和策略為某對象設(shè)置關(guān)聯(lián)對象值。
idobjc_getAssociatedObject(idobject,void*key)此方法根據(jù)給定的鍵從某對象中獲取相應(yīng)的關(guān)聯(lián)對象值毁靶。
voidobjc_removeAssociatedObjects(idobject)此方法移除指定對象的全部關(guān)聯(lián)對象胧奔。
關(guān)聯(lián)對象類型 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 等效的@property
OBJC_ASSOCIATION_ASSIGN ? ? ? ? ? assign
_RETAIN_NONATOMIC ? ? ? ? ? ? ? ? ? ? ? ?nonatomic,retain
...
11.理解objc_msgSend的作用
消息由接受者预吆,selector及參數(shù)構(gòu)成龙填。給某對象“發(fā)送消息”也就相當(dāng)于在該對象上調(diào)用方法。
發(fā)給某對象的全部消息都要由“動態(tài)消息派發(fā)系統(tǒng)”來處理拐叉,該系統(tǒng)會查出對應(yīng)的方法岩遗,并執(zhí)行其代碼。
id returnValue = [someObject messageName:parameter];
編譯器看到消息后將其轉(zhuǎn)換為標(biāo)準的C語言函數(shù)調(diào)用巷嚣,原型是:
void objc_msgSend(id self,SEL cmd,...)
轉(zhuǎn)換后:
id returnValue = objc_msgSend(someObject,@selector(messageName:),parameter);
12.理解消息轉(zhuǎn)發(fā)機制
若對象無法響應(yīng)某個selector喘先,則進入消息轉(zhuǎn)發(fā)流程。
通過運行期的動態(tài)方法解析功能廷粒,我們可以在需要用到某個方法時再將其加入類中。
對象可以將其無法解讀的某些selector轉(zhuǎn)交給其他對象處理红且。
經(jīng)過上述兩步后坝茎,如果還是沒辦法處理selector,那就啟動完整的消息轉(zhuǎn)發(fā)機制暇番。
13.用method swizzling調(diào)試黑盒方法
在runtime中嗤放,可以向類中新增或替換selector所對應(yīng)的方法實現(xiàn)。
使用另一份實現(xiàn)來替換原有的方法實現(xiàn)壁酬,這道工序叫做method swizzling次酌,開發(fā)者常用此技術(shù)向原有視線中添加功能。
一般來說舆乔,只有調(diào)試程序的時候才需要在runtime中修改方法實現(xiàn)岳服,這種做法不宜濫用。
//獲取方法實現(xiàn)
Method originalMethod =class_getInstanceMethod([NSStringclass],@selector(lowercaseSting));
Method swappedMethod =class_getInstanceMethod([NSStringclass],@selector(uppercaseString));
//交換方法
method_exchangeImplementations(originalMethod, swappedMethod);
14.理解“類對象”的用意
每個實例都有一個指向Class對象的指針希俩,用以表明其類型吊宋,而這些Class對象則構(gòu)成了類的繼承體系。
如果對象類型無法在編譯期確定颜武,那么就應(yīng)該使用類型信息查詢方法來探知璃搜。
盡量使用類型信息查詢方法來確定對象類型拖吼,而不要直接比較類對象,因為某些對象可能實現(xiàn)了消息轉(zhuǎn)發(fā)功能这吻。
對象都有isa指針吊档,指向的是對象的元類(metaclass)
id 中也包含isa指針,id對象定義
typedef struct objc_object{
Class isa;
} *id;
三唾糯、接口與API設(shè)計
15.用前綴避免命名空間沖突
選擇與你公司籍铁、應(yīng)用程序或者二者皆有關(guān)聯(lián)之名稱作為類名的前綴,并在所有代碼中均使用這一前綴趾断。
若自己所開發(fā)的程序庫中用到了第三方庫拒名,則應(yīng)為其中的名稱加上前綴。
Apple宣稱保留使用所有兩字母前綴的權(quán)利芋酌,所以自己所選用的前綴最好是三字母的增显。
比如你的程序中引用了XYZLibrary,想要發(fā)布脐帝,那么應(yīng)該都改為YDXYZLibrary,防止直接他人引入XYZLibrary產(chǎn)生沖突
16.提供“全能初始化方法”
在類中提供一個全能初始化方法同云,并于文檔里指明。其它初始化方法均應(yīng)調(diào)用此方法堵腹。
若全能初始化方法與超類不同炸站,則需覆寫超類中對應(yīng)方法。
如果超類的初始化方法并不適用于子類疚顷,那么應(yīng)該覆寫這個超類方法旱易,并在其中拋出異常。
拋出異常方法:
@throw[NSExceptionexceptionWithName:NSInternalInconsistencyExceptionreason:@"Must use initWithDimension:instead."userInfo:nil];
17.實現(xiàn)description方法
實現(xiàn)description方法返回一個有意義的字符串腿堤,用以描述該實例阀坏。
若想在調(diào)試時打印出更詳盡的對象描述信息,則應(yīng)該實現(xiàn)debugDescription方法笆檀。
//name,age 為對象屬性
- (NSString*)description{
return [NSString stringWithFormat:@"%@ %d",_name,_age];
}
- (NSString*)debugDescription{
return [NSString stringWithFormat:@"<%@: %p,\"%@ %d\">",[self ?class],self,_name,_age];
}
18.盡量使用不可變對象
盡量創(chuàng)建不可變的對象忌堂。
若某屬性僅可于對象內(nèi)部修改,則在“class-continuation分類”中將其由readonly屬性擴展為readwrite屬性酗洒。
不要把可變的collection作為屬性公開士修,而應(yīng)提供相關(guān)方法,一次修改對象中的可變collection樱衷。
擴展例子
.h 中
@property(nonatomic,copy,readonly)NSString*someString;
//提供初始化方法
- (instancetype)initWithSomeString:(NSString*)someString;
.m中class-continuation 中
@property(nonatomic,copy,readwrite)NSString*someString;
@property(nonatomic,strong,readwrite)dispatch_queue_tsyncQueue;
.m中
//派發(fā)隊列防止發(fā)生“競爭條件”
_syncQueue=dispatch_queue_create("com.manqian.syncQueue",NULL);
- (NSString*)someString{
__blockNSString*localSomeString;
dispatch_sync(_syncQueue, ^{
localSomeString =_someString;
});
returnlocalSomeString;
}
- (void)setSomeString:(NSString*)someString
{
dispatch_barrier_async(_syncQueue, ^{
_someString= someString;
});
}
19.使用清晰而協(xié)調(diào)的命名方式
起名時應(yīng)遵從標(biāo)準的Objective-C命名規(guī)范棋嘲,這樣創(chuàng)建出來的接口更容易為開發(fā)者所理解。
方法名要言簡意賅箫老,從左至右讀起來要像個日常用語中的句子才好封字。
方法名利不要使用縮略后的類型名稱。
給方法嗎起名時的第一要務(wù)就是確保其風(fēng)格與你自己的代碼或所要集成的框架相符。
繼承至UIView的子類阔籽,類名末尾一定是View流妻,同理其他的也需要這樣
20.為私有方法名加前綴
給私有方法的名稱加上前綴,這樣可以很容易的將其通公共方法區(qū)分開笆制。
不要單用一個下劃線做私有方法的前綴绅这,因為這種做法的預(yù)留給蘋果公司用的。
建議私有方法用p_ 開頭在辆,如
- (void)p_privateMethod {
/* … */
}
21.理解Objective-C錯誤模型
只有發(fā)生了可使整個應(yīng)用程序崩潰的嚴重錯誤時证薇,才使用異常。
在錯誤不那么嚴重的情況下匆篓,可以指派委托方法來處理錯誤浑度,也可把錯誤信息放在NSError對象里,經(jīng)由輸出參數(shù)返回給調(diào)用者鸦概。
NSError ** 會轉(zhuǎn)化為 ?MSError *__autoreleasing*
意為 指向指針的指針
22.理解NSCopying協(xié)議
若想令自己所寫的對象具有拷貝功能箩张,則需實現(xiàn)NSCopying協(xié)議。
如果自定義的對象分為可變版本與不可變版本窗市,那么就要同時實現(xiàn)NSCopying與NSMutableCopying協(xié)議先慷。
復(fù)制對象時需決定采用淺拷貝還是深拷貝,一般情況下應(yīng)該盡量執(zhí)行淺拷貝咨察。
如果你所寫的對象需要深拷貝论熙,那么可考慮新增一個專門執(zhí)行深拷貝的方法。
NSCopying協(xié)議只有一個方法
- (id) copyWithZone:(NSZone *)zone ?//zone 區(qū)摄狱,每個程序只有一個“默認區(qū)”
深拷貝 會新建一個對象脓诡,原來的對象被銷毀了,深拷貝的對象不會被銷毀
淺拷貝 不會新建對象二蓝,只是新增了一個指針指向原來的對象誉券,原來的對象被銷毀,淺拷貝的東西也被銷毀
四刊愚、協(xié)議與分類
23.通過委托與數(shù)據(jù)源協(xié)議進行對象間通信
委托模式為對象提供了一套接口,使其可由此將相關(guān)事件告知其他對象踩验。
將委托對象應(yīng)該支持的接口定義成協(xié)議鸥诽,在協(xié)議中把可能需要吃力的事件定義成方法。
當(dāng)某對象需要從另外一個對象中獲取數(shù)據(jù)時箕憾,可使用委托模式牡借。在這種情況下,該模式亦稱數(shù)據(jù)源協(xié)議袭异。
若有必要钠龙,可實現(xiàn)含有位段的結(jié)構(gòu)體,將委托對象是否能響應(yīng)相關(guān)協(xié)議方法這一信息緩存至其中。
數(shù)據(jù)流向
Data Source —>class—>Delegate
#import <Foundation/Foundation>
@classYDNetworkFetcher;
@protocolYDNetworkFetcherDelegate
@optional
- (void)networkFetcher:(YDNetworkFetcher*)fetcher didReceiveData:(NSData*)data;
- (void)networkFetcher:(YDNetworkFetcher*)fetcher didFailWithError:(NSError*)error;
- (void)networkFetcher:(YDNetworkFetcher*)fetcher didUpdateProgressTo:(float*)progress;
@end?
@interfaceYDNetworkFetcher :NSObject
/***設(shè)置代理*/
@property(nonatomic,weak)id delegate;
@end
#import"YDNetworkFetcher.h"
@interfaceYDNetworkFetcher()
{
struct{
unsignedintdidReceiveData :1;
unsignedintdidFailWithError :1;
unsignedintdidUpdateProgressTo :1;
} _delegateFlags;
}
@end
@implementationYDNetworkFetcher
- (void)setDelegate:(id)delegate{
iddelegateObject = delegate;
_delegate= delegate;
//將代理是否執(zhí)行方法緩存起來
_delegateFlags.didReceiveData= [delegateObjectrespondsToSelector:@selector(networkFetcher:didReceiveData:)];
_delegateFlags.didFailWithError= [delegateObjectrespondsToSelector:@selector(networkFetcher:didFailWithError:)];
_delegateFlags.didUpdateProgressTo= [delegateObjectrespondsToSelector:@selector(networkFetcher:didUpdateProgressTo:)];
}
- (void)networkFetcher:(YDNetworkFetcher*)fetcher didReceiveData:(NSData*)data
{
//不需要每次都去查找是否實現(xiàn)該方法
if(_delegateFlags.didReceiveData) {
[_delegatenetworkFetcher:selfdidReceiveData:data];
}
}
- (void)networkFetcher:(YDNetworkFetcher*)fetcher didFailWithError:(NSError*)error{
if(_delegateFlags.didFailWithError) {
[_delegatenetworkFetcher:selfdidFailWithError:error];
}
}
- (void)networkFetcher:(YDNetworkFetcher*)fetcher didUpdateProgressTo:(float*)progress{
if(_delegateFlags.didUpdateProgressTo) {
[_delegatenetworkFetcher:selfdidUpdateProgressTo:progress];
}
}
@end
24.將類的實現(xiàn)代碼分散到便于管理的數(shù)個分類之中
使用分類機制把類的實現(xiàn)代碼劃分成易于管理的小塊碴里。
將應(yīng)該視為私有的方法歸入名叫Private的分類中沈矿,以隱藏實現(xiàn)細節(jié)。
@interfaceYDPerson :NSObject
@property(nonatomic,copy)NSString*firstName;
@property(nonatomic,copy)NSString*lastName;
@property(nonatomic,strong)NSArray*friends;
- (instancetype)initWithFirstName:(NSString*)firstName
LastName:(NSString*)lastName
Friends:(NSArray*)friends;
@end
@interfaceYDPerson (Friendship)
- (void)addFriend:(YDPerson*)person;
- (void)removeFriends:(YDPerson*)person;
- (BOOL)isFriendsWith:(YDPerson*)person;
@end
@interfaceYDPerson (Work)
- (void)performDaysWork;
- (void)takeVacationFromWork;
@end
@interfaceYDPerson (Play)
- (void)goToTheCinema;
- (void)goToSportsGame;
@end
25.總是為第三方類的分類名稱加前綴
向第三方類中添加分類時咬腋,總應(yīng)給其名稱加上你專用的前綴羹膳。
向第三方類中添加分類時,總應(yīng)給其中的方法名加上你專用的前綴根竿。
26.勿在分類中聲明屬性
把封裝數(shù)據(jù)所用的全部屬性都定義在主接口里陵像。
在class-continuation分類之外的其他分類中,可以定義存取方法寇壳,但盡量不要定義屬性醒颖。
27.使用class-continuation分類隱藏實現(xiàn)細節(jié)
通過class-continuation分類向類中新增實例變量。
如果某屬性在主接口中聲明為只讀壳炎,而類的內(nèi)部又要用設(shè)置方法修改此屬性泞歉,那么就在class-continuation分類中將其擴展為可讀寫。
把私有方法的原型聲明在class-continuation分類里面冕广。
若想使類遵循的協(xié)議不為人所知疏日,則可于class-continuation分類中聲明。
28.通過協(xié)議提供匿名對象
協(xié)議可在某種程度上提供匿名類型撒汉。具體的對象類型可以淡化成遵從某些一的id類型沟优,協(xié)議里規(guī)定了對象所應(yīng)實現(xiàn)的方法。
使用匿名對象來隱藏類型名稱或類名睬辐。
如果具體類型不重要挠阁,重要的是對象能夠響應(yīng)(定義在協(xié)議里的)特定方法,那么可使用匿名對象來表示溯饵。