《Effective Objective-C 2.0編寫高質量iOS與OS X代碼的52個方法》要點回顧(四)第四章 協議與分類

OC中兩項重要的語言特性:

  • 協議:與Java中的“接口”類似,但不支持多重繼承,最常見的用途是實現委托模式

    多重繼承指的是一個類可以同時繼承多個類,比如A類繼承自B類和C類,這就是多重繼承。

  • 分類:利用分類機制,我們無須繼承子類即可直接為當前類添加方法。因為OC運行期系統是高度動態的,但也隱藏著一些陷阱。

23. 通過委托與數據源協議進行對象間通信

@property (nonatomic, weak) id <xxxxDelegate> delegate;

如果是方法是可選的(optional),在委托類中,需要先執行判斷(responseToSelector)操作。

if ([_delegate responseToSelector:@selector(xxxxx)]) {
    [_delegate xxxxx];
}
完整的例子:
//
//  EOCNetworkFetcher.h
//

#import <Foundation/Foundation.h>

@class EOCNetworkFetcher;
@protocol EOCNetworkFetcherDelegate <NSObject>

@optional
- (void)networkFetcher:(EOCNetworkFetcher *)fetcher didReceiveData:(NSData *)data;

- (void)networkFetcher:(EOCNetworkFetcher *)fetcher didFailWithError:(NSError *)error;

- (void)networkFetcher:(EOCNetworkFetcher *)fetcher didUpdateProgressTo:(float)progress;

@end

@interface EOCNetworkFetcher : NSObject

@property (nonatomic, weak) id <EOCNetworkFetcherDelegate> delegate;

- (void)requestWithParams:(id)params url:(NSURL *)url;


@end
/*******************************************/
/*******************************************/
//
//  EOCNetworkFetcher.m
//

#import "EOCNetworkFetcher.h"

@interface EOCNetworkFetcher (){
    /**
    這個結構體,用來緩存委托對象是否能響應特定的選擇子
    2^1 = 2,表示0 和 1 兩個數。
    */
    struct {
        unsigned int didReceiveData: 1;
        unsigned int didFailWithError: 1;
        unsigned int didUpdateProgressTo: 1;
    } _delegateFlags;
}
@end

@implementation EOCNetworkFetcher {}

- (void)setDelegate:(id<EOCNetworkFetcherDelegate>)delegate {
    
    _delegate = delegate;
    
    /* 優化代碼執行速度
     這樣就不用每次在實現要被代理的方法前,每次執行檢查了。只要檢查一次就好。因為在設置代理時就已經確定了。
     */
    _delegateFlags.didReceiveData = [delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)];
    _delegateFlags.didFailWithError = [delegate respondsToSelector:@selector(networkFetcher:didFailWithError:)];
    _delegateFlags.didUpdateProgressTo = [delegate respondsToSelector:@selector(networkFetcher:didUpdateProgressTo:)];
    
}

- (void)requestWithParams:(id)params url:(NSURL *)url {
    
    if (_delegateFlags.didReceiveData) {
        [_delegate networkFetcher:self didReceiveData:[NSData new]];
    }
    
    if (_delegateFlags.didFailWithError) {
        [_delegate networkFetcher:self didFailWithError:[NSError new]];
    }
    
    if (_delegateFlags.didUpdateProgressTo) {
        [_delegate networkFetcher:self didUpdateProgressTo:1.0f];
    }
}

@end

要點

  • 委托模式為對象提供了一套接口,使其可由此將相關事件告知其他對象。
  • 將委托的對象應該支持的接口定義成協議,在協議中將可能需要的事件定義成方法。
  • 當某一對象需要從另一對象獲取數據時,可以使用委托模式。在這種情況下,該協議被稱為 “數據源協議”。
  • 若有必要,可實現含有位段的結構體,將委托對象是否響應相關代理方法 這一信息緩存至其中。

在結構體中,
fileA 位段將占用8個二進制位,0~255;
fileB 位段將占用4個二進制位,0~16;
fileC 位段將占用2個二進制位,0~4;
fileD 位段將占用1個二進制位,0~1;

struct file {
    unsigned int fileA: 8;
    unsigned int fileB: 4;
    unsigned int fileC: 2;
    unsigned int fileD: 1;
} ;

24. 將類的實現代碼分散到便于管理的數個分類之中

要點
  • 使用 分類機制 把類的實現代碼劃分為易于管理的小塊。
  • 將應該視為 “私有” 的方法歸入名為 “private” 的分類中,用以隱藏實現細節。

將類代碼打散到分類中,便于調試

  1. 調試會出現分類名稱,如-[EOCPerson(FriendShip) addFriend:]
  2. 方便查看,可以給類進行“瘦身”。

25. 總是為第三方類的分類名稱加上前綴

@interface NSString (WZZ_HTTP)

- (NSString *)wzz_doSomeThing1;

- (NSString *)wzz_doSomeThing2;

@end
要點總結
  • 向第三方類中添加分類時,總應給其 名稱 和其中的 方法 加上你專用的前綴。----避免多次覆蓋

26. 勿在分類中聲明屬性

屬性,是用來封裝數據的。

要點
  • 把封裝數據所用的全部屬性都定義在 主接口 里;
  • 在 “class-continuation 分類” 之外的所有分類里,可以定義存取 方法 ,但不應聲明 屬性 。

27. 使用 “class-continuation” 分類實現隱藏細節

@interface EOCPerson ()

@end

//或
@implementation EOCPerson

@end
要點
  • 通過 “class—continuation分類” ,向類中增加實例變量。
  • 如果屬性在主接口聲明中為“只讀” ,而類的內容又要用設置方法修改此屬性,那么就在 “class-continuation分類” 中將其擴展為可讀寫。
//.h 中
@property (nonatomic, copy, readOnly) NSString *name;

//.m 中
@property (nonatomic, copy, readWrite) NSString *name;
  • 把私有方法的原型聲明在 “class-continuation分類” 里面。
//.m
@interface EOCPerson ()
- (void)p_privateMethod;//私有方法
@end
  • 若想隱藏此類所實現的協議,則可在該類的 “class-continuation分類” 中聲明。
//.m
@interface EOCPerson() <EOCSecretDelegate>
@end

28. 通過協議提供匿名對象

要點
- (id<EOCSecretProtocol>)doSomeThing;
  • 協議在某種程度上可以提供匿名類型。具體的類型可以淡化成遵從某協議的id類型,協議里規定了對象所應實現的代理方法。
  • 使用匿名對象來隱藏類型名稱(或類名)
  • 如果類型不重要,重要的是對象能夠響應(某個協議的)特定方法,那么可以使用你匿名對象來表示。

系列文章

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容