編寫高質(zhì)量代碼的52個(gè)有效方法(七)---系統(tǒng)框架

outstanding.png

47.熟悉系統(tǒng)框架

框架:將一系列代碼封裝為動(dòng)態(tài)庫(dynamic library),并在其中放入描述其接口的頭文件班挖,這樣做出來的東西叫做框架。

在為Mac OS X或iOS系統(tǒng)開發(fā)“帶圖形界面的應(yīng)用程序”時(shí)芯砸,會(huì)用到名為Cocoa的框架萧芙,在iOS上稱為Cocoa Touch。其實(shí)Cocoa本身并不是框架假丧,但是里面集成了一批創(chuàng)建應(yīng)用程序時(shí)經(jīng)常會(huì)用到的框架双揪。

要點(diǎn):

  1. 許多系統(tǒng)框架都可以直接使用。其中最重要的是Foundation與CoreFoundation,這兩個(gè)框架提供了構(gòu)建應(yīng)用程序所需要的許多核心功能包帚;
  2. 很多常見任務(wù)都能用框架來做渔期,例如音頻與視頻處理、網(wǎng)絡(luò)通信渴邦,數(shù)據(jù)管理等疯趟;
  3. 請(qǐng)記住:用純C寫成的框架與ObjectiveC寫成的一樣重要谋梭,若想成為優(yōu)秀的Objective-C開發(fā)者信峻,應(yīng)該掌握C語言的核心概念。

48.多用塊枚舉瓮床,少用for循環(huán)

//三個(gè)舉例集合
NSArray *array = @[@1,@2,@3];
    NSDictionary *dict = @{
                           @"key1":@"value1",
                           @"key2":@"value2",
                           @"key3":@"value3"
                           };
    
NSSet *set = [[NSSet alloc] initWithObjects:@"str1",@"str2",@"str3", nil];
    
//for 循環(huán)
for (int i = 0; i < array.count; i++) {
    id object = array[i];
    //do something with object
}
    
//對(duì)于字典中間做一個(gè)allkeys的轉(zhuǎn)換
NSArray *keys = [dict allKeys];
    
//對(duì)于set集合中間做一個(gè)allobjects的轉(zhuǎn)換
NSArray *objects = [set allObjects];


//Objective-C 1.0的NSEnumerator來遍歷
- (NSArray *)allObjects;
- (id)nextObject;


//Objective-C 1.0的NSEnumerator來遍歷
NSEnumerator *enumerator = [array objectEnumerator];
id object;//若知道具體類型盹舞,可直接寫成具體類型
while ((object = [enumerator nextObject]) != nil) {
    //do something with object
}
    
NSEnumerator *dicEnumerator = [dict keyEnumerator];
id key;//若知道具體類型产镐,可直接寫成具體類型
while ((key = [dicEnumerator nextObject]) != nil) {
    id value = [dict objectForKey:key];//若知道具體類型,可直接寫成具體類型
    // do something with value
}
    
NSEnumerator *setEnumerator = [set objectEnumerator];
id setObject;//若知道具體類型矾策,可直接寫成具體類型
while ((setObject = [setEnumerator nextObject]) != nil) {
       // do something with object
}
    
#warning !!!若需要反向遍歷磷账,則可以使用反向枚舉器
[array reverseObjectEnumerator];



//Objective-C 2.0的快速遍歷  for in
    
for (id object in array) {
    // do something with object
}
    
for (id key in dict) {
    id object = [dict objectForKey:key];
    // do something with object
}
    
for (id object in set) {
    // do something with object
}


//基于塊的遍歷方式
[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    // do something with object    
}];
    
[dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
    // do something with object    
}];
    
[set enumerateObjectsUsingBlock:^(id  _Nonnull obj, BOOL * _Nonnull stop) {
    // do something with object    
}];
    
//若要反向遍歷,則可使用帶有“選項(xiàng)掩碼”(option mask)的方法
[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    // do something with object    
}];

要點(diǎn):

  1. 遍歷collection有四種方式贾虽。最基本的辦法是for循環(huán)逃糟,其次是NSEnumeratior遍歷法及快速遍歷法,最新蓬豁、最先進(jìn)的方式則是“塊枚舉法”绰咽。
  2. “塊枚舉法”本身就能通過GCD來并發(fā)執(zhí)行遍歷操作,無須另行編寫代碼地粪。而采用其他遍歷方式則無法輕易實(shí)現(xiàn)這一點(diǎn)取募。
  3. 若提前知道待遍歷的collection含有何種對(duì)象,則應(yīng)修改塊簽名蟆技,指出對(duì)象的具體類型玩敏。

49.對(duì)自定義其內(nèi)存管理語義的collection使用無縫橋接

要點(diǎn):

  1. 通過無縫橋接技術(shù),可以在Foundation框架中的Objective-C對(duì)象與CoreFoundation框架中的C語言數(shù)據(jù)結(jié)構(gòu)之間來回轉(zhuǎn)換质礼。
  2. 在CoreFoundation層面創(chuàng)建collection時(shí)旺聚,可以指定許多回調(diào)函數(shù),這些函數(shù)表示此collection應(yīng)如何處理其元素眶蕉。然后砰粹,可運(yùn)用無縫橋接技術(shù),將其轉(zhuǎn)換成具備特殊內(nèi)存管理語義的Objective-C collection造挽。

50.構(gòu)建緩存時(shí)碱璃,選用NSCache而非NSDictionary

之前在閱讀SDWebImage源碼時(shí),有看到里面緩存使用的就是NSCache,其使用可查看文章
關(guān)于緩存類NSCache

要點(diǎn):

  1. 實(shí)現(xiàn)緩存時(shí)應(yīng)選用NSCache而非NSDictionary對(duì)象饭入。因?yàn)镹SCache可以提供優(yōu)雅的自動(dòng)刪減功能嵌器,而且是“線程安全的”,此外谐丢,它與字典不同嘴秸,并不會(huì)拷貝鍵。
  2. 可以給NSCache對(duì)象設(shè)置上限庇谆,用以限制緩存中的對(duì)象總個(gè)數(shù)及“總成本”岳掐,而這些尺度則定義了緩存刪減其中對(duì)象的時(shí)機(jī)。但是絕對(duì)不要把這些尺度當(dāng)成可靠的“硬限制”饭耳,他們僅對(duì)NSCache起知道作業(yè)
  3. 將NSPurgeableData與NSCache搭配使用串述,可實(shí)現(xiàn)自動(dòng)清除數(shù)據(jù)的功能,也就是說寞肖,當(dāng)NSPurgeableData對(duì)象所占內(nèi)存為系統(tǒng)所丟棄時(shí)纲酗,該對(duì)象自身也會(huì)從緩存中移除衰腌。
  4. 如果緩存使用得當(dāng),那么應(yīng)用程序的響應(yīng)速度就能提高觅赊。只有那種“重新計(jì)算起來很費(fèi)事的”數(shù)據(jù)右蕊,才值得放入緩存,比如那些需要從網(wǎng)絡(luò)獲取或從磁盤讀取的數(shù)據(jù)

51.精簡(jiǎn)initialize與load的實(shí)現(xiàn)代碼

+ (void)load; //(加載進(jìn)系統(tǒng)時(shí)調(diào)用)
+ (void)initialize;//(類在使用前的初始化調(diào)用吮螺,系統(tǒng)調(diào)用)

// + (void)load
對(duì)于加入運(yùn)行期系統(tǒng)中的每個(gè)類(class)及分類(category)來說饶囚,必定會(huì)調(diào)用此方法,而且僅調(diào)用一次。當(dāng)包含類或分類的程序庫載入系統(tǒng)時(shí)鸠补,就會(huì)執(zhí)行此方法萝风,而這通常就是指應(yīng)用程序啟動(dòng)的時(shí)候,若程序是為iOS平臺(tái)設(shè)計(jì)的紫岩,則肯定會(huì)在此時(shí)執(zhí)行规惰。如果分類和其所屬的類都定義了load方法,則先調(diào)用類里面的歇万,再調(diào)用分類里的,因?yàn)榉诸惱锩婵赡軙?huì)使用到類里面的方法勋陪。

有個(gè)重要的事情需注意堕花,那就是load方法并不像普通的方法那樣粥鞋,它并不遵從那套繼承規(guī)則。如果某個(gè)類本身沒實(shí)現(xiàn)load方法瞄崇,那么不管其各級(jí)超類是否實(shí)現(xiàn)此方法呻粹,系統(tǒng)都不會(huì)調(diào)用。

而且load方法務(wù)必實(shí)現(xiàn)的精簡(jiǎn)一些苏研,也就是要盡量減少其所執(zhí)行的操作等浊,因?yàn)檎麄€(gè)應(yīng)用程序在執(zhí)行l(wèi)oad方法時(shí)都會(huì)阻塞。如果load方法中包含繁雜的代碼摹蘑,那么應(yīng)用程序在執(zhí)行期間就會(huì)變得無響應(yīng)筹燕。不要在里面等待鎖,也不用調(diào)用可能加鎖的方法衅鹿。

//+ (void)initialize;
對(duì)于每個(gè)類來說撒踪,該方法會(huì)在程序首次使用該類之前調(diào)用,且只調(diào)用一次大渤。它是由運(yùn)行期系統(tǒng)來調(diào)用的制妄,絕不應(yīng)該通過代碼直接調(diào)用。

首先泵三,它是“惰性調(diào)用的”耕捞,也就是說衔掸,只有當(dāng)程序用到了相關(guān)的類時(shí),才會(huì)調(diào)用俺抽。因此敞映,如果某個(gè)類一直沒有使用,那么其initialize方法就一直不會(huì)運(yùn)行磷斧。這也就是說振愿,應(yīng)用程序無須先把每個(gè)類的initialize都執(zhí)行一遍,這與load方法不同瞳抓,對(duì)于load來說埃疫,應(yīng)用程序必須阻塞并等著所有類的load都執(zhí)行完,才能繼續(xù)孩哑。

其次栓霜,此方法與load方法還有個(gè)區(qū)別,就是運(yùn)行期系統(tǒng)在執(zhí)行該方法時(shí)横蜒,是處于正常狀態(tài)的胳蛮,因此,從運(yùn)行期系統(tǒng)完整度上來講丛晌,此時(shí)可以安全使用并調(diào)用任意類中的任意方法仅炊。而且,運(yùn)行期系統(tǒng)也能確保initialize方法一定會(huì)在“線程安全的環(huán)境”中執(zhí)行澎蛛,這就是說抚垄,只有執(zhí)行initialize的那個(gè)線程可以操作類或類實(shí)例。其他線程都要先阻塞谋逻,等著initialize執(zhí)行完呆馁。

最后,initialize方法與其他消息一樣毁兆,如果某個(gè)類未實(shí)現(xiàn)它浙滤,而其超類實(shí)現(xiàn)了,那么就會(huì)運(yùn)行超類的實(shí)現(xiàn)代碼气堕。

要點(diǎn):

  1. 在加載階段纺腊,如果類實(shí)現(xiàn)了load方法,那么系統(tǒng)就會(huì)調(diào)用它茎芭。分類里也可以定義此方法揖膜,類的load方法要比分類中的先調(diào)用。與其他方法不同梅桩,load方法不參與覆寫機(jī)制次氨。
  2. 首次使用某個(gè)類之前,系統(tǒng)會(huì)向其發(fā)生initialize消息摘投。由于此方法遵從普通的覆寫規(guī)則煮寡,所以通常應(yīng)該在里面判斷當(dāng)前要初始化的是哪個(gè)類虹蓄。
  3. load與initialize方法都應(yīng)該實(shí)現(xiàn)的精簡(jiǎn)一些,這有助于保持應(yīng)用程序的響應(yīng)能力幸撕,也能減少引入“依賴環(huán)”的幾率薇组。
  4. 無法在編譯期設(shè)定的全局常量,可以放在initialize方法里初始化坐儿。

52.別忘了NSTimer會(huì)保留其目標(biāo)對(duì)象

#import <Foundation/Foundation.h>

@interface NSTimer (BlockTimer)

+ (NSTimer *)timer_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats;

@end



#import "NSTimer+BlockTimer.h"

@implementation NSTimer (BlockTimer)


+ (NSTimer *)timer_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats
{
    return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(timer_blockInvoke:) userInfo:[block copy] repeats:repeats];
}

+ (void)timer_blockInvoke:(NSTimer *)timer
{
    void (^block)(void) = timer.userInfo;
    if (block) {
        block();
    }
}

@end



//use

//本類擁有實(shí)例變量 _timer
- (void)startTimer
{
    __weak typeof(self) weakSelf = self;
    
    _myTimer = [NSTimer timer_scheduledTimerWithTimeInterval:5.0 block:^{
        ViewController *strongSelf = weakSelf;
        [strongSelf dosomething];
    } repeats:YES];
}

- (void)dosomething
{
    
}

- (void)stopTimer
{
    [_myTimer invalidate];
    _myTimer = nil;
}

- (void)dealloc
{
    [_myTimer invalidate];
}

要點(diǎn):

  1. NSTimer對(duì)象會(huì)保留其目標(biāo)律胀,直到計(jì)時(shí)器本身失效為止,調(diào)用invalidate方法可令計(jì)時(shí)器失效貌矿,另外炭菌,一次性的計(jì)時(shí)器在觸發(fā)任務(wù)之后也會(huì)失效。
  2. 反復(fù)執(zhí)行任務(wù)的計(jì)時(shí)器逛漫,很容易引入保環(huán)黑低,如果這種計(jì)時(shí)器的目標(biāo)對(duì)象又保留了計(jì)時(shí)器本身,那肯定會(huì)導(dǎo)致保留環(huán)酌毡。這種環(huán)狀保留關(guān)系克握,可能是直接發(fā)生的,也可能是通過其他對(duì)象間接發(fā)生的枷踏。
  3. 可以擴(kuò)充NSTimer的功能菩暗,用“塊”來打破保留環(huán)。不過旭蠕,除非NSTimer將來在公共接口里提供此功能停团,否則必須創(chuàng)建分類,將相關(guān)實(shí)現(xiàn)代碼加入其中掏熬。



PDF格式的資料來自iOS開發(fā)交流群佑稠、感覺作者的貢獻(xiàn),對(duì)于知識(shí)的系統(tǒng)歸納總結(jié)很有幫助孽江。
編寫高質(zhì)量代碼的52個(gè)有效方法
編寫高質(zhì)量代碼的52個(gè)有效方法(一)—熟悉OC
編寫高質(zhì)量代碼的52個(gè)有效方法(二)—對(duì)象、消息番电、運(yùn)行期
編寫高質(zhì)量代碼的52個(gè)有效方法(三)—接口與API設(shè)計(jì)
編寫高質(zhì)量代碼的52個(gè)有效方法(四)—協(xié)議與分類
編寫高質(zhì)量代碼的52個(gè)有效方法(五)—內(nèi)存管理
編寫高質(zhì)量代碼的52個(gè)有效方法(六)—塊與大中樞派發(fā)
編寫高質(zhì)量代碼的52個(gè)有效方法(七)---系統(tǒng)框架

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末岗屏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子漱办,更是在濱河造成了極大的恐慌这刷,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娩井,死亡現(xiàn)場(chǎng)離奇詭異暇屋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)洞辣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門咐刨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昙衅,“玉大人,你說我怎么就攤上這事定鸟《妫” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵联予,是天一觀的道長(zhǎng)啼县。 經(jīng)常有香客問我,道長(zhǎng)沸久,這世上最難降的妖魔是什么季眷? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮卷胯,結(jié)果婚禮上子刮,老公的妹妹穿的比我還像新娘。我一直安慰自己诵竭,他們只是感情好话告,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卵慰,像睡著了一般沙郭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上裳朋,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天病线,我揣著相機(jī)與錄音,去河邊找鬼鲤嫡。 笑死送挑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的暖眼。 我是一名探鬼主播惕耕,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼诫肠!你這毒婦竟也來了司澎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤栋豫,失蹤者是張志新(化名)和其女友劉穎挤安,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丧鸯,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蛤铜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片围肥。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡剿干,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出虐先,到底是詐尸還是另有隱情怨愤,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布蛹批,位于F島的核電站撰洗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏腐芍。R本人自食惡果不足惜差导,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望猪勇。 院中可真熱鬧设褐,春花似錦、人聲如沸泣刹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽椅您。三九已至外冀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掀泳,已是汗流浹背雪隧。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留员舵,地道東北人脑沿。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像马僻,于是被迫代替她去往敵國(guó)和親庄拇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容