1. 了解 Objective-C 語言的起源
Objective-C 語言使用”消息結(jié)構(gòu)”而非”函數(shù)調(diào)用”.Objective-C 語言由 Smalltalk演化而來,后者是消息類型語言的鼻祖.編譯器甚至不關(guān)心接收消息對象的何種類型.接收消息的對象問題也要在運(yùn)行時處理,其過程叫做”動態(tài)綁定”.
Objective-C為 C 語言添加了面向?qū)ο筇匦?是其超類. Objective-C 使用動態(tài)綁定的消息結(jié)構(gòu),也就是說,在運(yùn)行時才會檢查對象類型.接收一條消息后,究竟應(yīng)執(zhí)行何種代碼,有運(yùn)行期環(huán)境而非編譯器決定.理解 C 語言的核心有助于寫好 Objective-C 程序.尤其是掌握內(nèi)存模型與指針.
2. 在類的頭文件中盡量少引用其他頭文件
Objective-C 語言編寫類的標(biāo)準(zhǔn)行為:以類名做文件名,分別闖將兩個文件,有文件后綴用. h,實現(xiàn)文件后綴用. m.
在開發(fā)中有時候我們會在. h 文件中引入很多用不到的內(nèi)容,這當(dāng)然會增加編譯時間.除非有必要,否則不要引入頭文件,一般來說,某個類的頭文件中使用向前聲明來體積別的類,并在實現(xiàn)文件中引入哪些類的頭文件,這樣做可以盡量降低類之間的耦合.有時無法使用前聲明,比如要聲明某個類遵循意向協(xié)議,這種情況下,盡量把 “該類遵循某協(xié)議”的這條聲明移至 class=continuation 分類中,如果不行的話,就把協(xié)議單獨(dú)存放在一個頭文件中,然后將其引入.
3. 多用字面量語法,少用與之等價的方法
NSArray *arr = [NSArray arrayWithObjects:@"num1",@"num2",@"num3", nil];
NSArray *arr = @[@"num1",@"num2",@"num3”];
字面量語法創(chuàng)建字符串,數(shù)組,數(shù)值,字典.與穿件此類對象的常規(guī)方法相比,這么做更加簡明扼要.
注意事項:
- 除了字符串以外,所創(chuàng)建的類必須屬于 Foundation 框架才行,如果自定義了這些類的子類,則無法用字面量語法創(chuàng)建其對象.
- 穿件的數(shù)組或字典時,若值有 nil, 則會拋出異常.因此,務(wù)必確保值中不含 nil.
4. 多用類型常量,少用# deine 預(yù)處理指令
不要用預(yù)處理指令定義常量,這樣定義出來的常量不含類型信息,編譯器只會在編譯前根據(jù)執(zhí)行查找與替換操作,即使有人重新定義了常量值,編譯器也不會產(chǎn)生井道信息,這將導(dǎo)致應(yīng)用程序常量值不一致.
static NSString *const PersonConstant = @"PersonConstantStr” ;
但是我個人認(rèn)為其實,還是#define用的多, 開發(fā)避免不了使用 pch文件. 如果有強(qiáng)迫癥的同學(xué),定義常量就想使用 staitc,extren,const這些關(guān)鍵字.那我建議新建一個專門存放這些常量的類,然后在 pch 中導(dǎo)入這個類.
- static 修飾符意味著該變量盡在定義此變量的單元中可見
- extern 全局變量
Person.h
#import <Foundation/Foundation.h>
static NSString *const PersonConstant;
@interface Person : NSObject
@end
Person.m
#import "Person.h"
static NSString *const PersonConstant = @"PersonConstantStr";
@implementation Person
@end
.pch
#define DefineStr @"DefineStr"
#import "Person.h"
#endif
5. 用枚舉表示狀態(tài),選項,狀態(tài)碼
應(yīng)該用枚舉來表示狀態(tài)機(jī)的狀態(tài),傳遞給方法的選項以及狀態(tài)碼等值,給這些值起個易懂的名字
enum PersonEnum{
PersonEnumNum1,
PersonEnumNum2,
PersonEnumNum3,
};
typedef enum PersonEnum PersonState;
6. 理解屬性這一概念
屬性是 Objective-C 的一項特性,用于封存對象中的數(shù)據(jù).
屬性特質(zhì):原子性 讀寫權(quán)限
內(nèi)存管理語義
- assign 這是方法只會執(zhí)行針對純量類型(CGFloat,NSInteger)的簡單賦值操作
- strong 此特質(zhì)表明該屬性定義一種擁有關(guān)系,為這種屬性設(shè)置新值時,這只方法會先保存新值,并釋放舊值
- weak 此特質(zhì)表明屬性定義了一種”非擁有關(guān)系”,為這種屬性設(shè)置新值是,設(shè)置方法既不保留新值,也不釋放舊值.此特質(zhì)同 assign 類似,然而在屬性所指對象遭到摧毀時,屬性值會清空
- unsafe_unretainde 此特質(zhì)與 assign 相同,它適用于對象類型,該特質(zhì)表達(dá)一種"非擁有關(guān)系”,當(dāng)目標(biāo)對象遭到摧毀時,屬性不會自動清空,因為它是不安全的,這一點(diǎn)與 weak 的區(qū)別
- copy 此特質(zhì)所表達(dá)的所屬關(guān)系與 strong 類似,然而設(shè)置方法并不保留新值,而是將其拷貝,多用于 NSString.
7. 在對象內(nèi)部盡量直接訪問實例變量
直接訪問實例變量的速度比較快,因為不經(jīng)過 Objective-C 方法派發(fā),編譯器所生成的代碼會直接訪問保存催下實例量的那塊內(nèi)存.
直接訪問實例變量時,不會調(diào)用設(shè)置方法,這就繞過了相關(guān)屬性所定義的內(nèi)存管理語義.
8. 理解"對象等同性”這一概念
根據(jù)等同性來比較對象是一個非常有用的功能,不過,按照==操作符比較出來的結(jié)果未必是我們想要的,因為該操作比較的事兩個指針本身,而不是其所指的對象.應(yīng)該使用 NSObject 協(xié)議中的聲明的”isEqual”方法來判斷兩個對象的等同性,一般來說兩個類型不同的對象總是不相等的.直接比較字符串的時候 isEqual 比 isEqualToString慢,因為前者還要執(zhí)行額外步驟.
9. 以"類族模式"隱藏實現(xiàn)細(xì)節(jié)
“類族”是一種很用用的模式,可以隱藏抽象基類背后實現(xiàn)的細(xì)節(jié). 這是一種”工廠模式”.比如iOS 用戶界面框架 UIKit 中就有一個名為 UIButton 的類.想創(chuàng)建按鈕,需要調(diào)用下面這個類方法.
+(UIButton*)buttonWithType:(UIButtonType)type;
我到是認(rèn)為,作者想告訴我我們要好好封裝代碼,這個地方?jīng)]啥好說的.
10. 在既有類中使用關(guān)聯(lián)對象存放自定義數(shù)據(jù)
有時需要在對象中存放相關(guān)信息,這是我們通常會從對象所屬的類中繼承一個子類,然后改用這個子類對象.然而并非所有情況下都這么做,有時候類的實例可能是由某種機(jī)制所創(chuàng)建的,而開發(fā)者無法令這種機(jī)制創(chuàng)建出自己所寫的實例. Objective-C 中有意向強(qiáng)大的特性可以解決問題,這就是關(guān)聯(lián)對象.
11. 理解objc_msgSend的作用
用Objetive-C的術(shù)語來說贺嫂,這叫做“消息傳遞”曲饱。這里說的是運(yùn)行時。
12. 理解消息轉(zhuǎn)發(fā)機(jī)制
當(dāng)對象接收到無法解讀的消息后,就會啟動消息轉(zhuǎn)發(fā)機(jī)制氛谜,程序員可經(jīng)此過程告訴對象應(yīng)該圖和處理未知消息杨何。這里說的是運(yùn)行時垃帅。
13. 用方法調(diào)配技術(shù)調(diào)試黑盒方法
運(yùn)行期間订讼,可以向類中新增或替換選擇子所對應(yīng)的方法實現(xiàn)定踱。
使用另一份實現(xiàn)來替換原有的方法實現(xiàn),這道工序叫做方法調(diào)配,開發(fā)者常用此技術(shù)想原有實現(xiàn)中添加新功能粤剧。
一般來說株憾,只有調(diào)試程序的時候才需要運(yùn)行期修改方法實現(xiàn),這種做法不易濫用郑藏。這里說的是運(yùn)行時擦耀。
14. 理解類對象的用意
每個Objective-C對象實例都是指向某塊內(nèi)存數(shù)據(jù)的指針汽纤,如果把對象所需的內(nèi)存分配到棧上編譯器就會報錯
每個對象結(jié)構(gòu)體的首個成員是Class類的變量,該變量定義了對象所屬的類瞳购,通常稱為isa指針碴萧。
typedef struct objc_class *class
struct objc_class{
Class isa;
Class super_class;
const char* name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list *ivars;
struct objc_cache *cache;
struct objc_protocol_list protocols;
}
此結(jié)構(gòu)體存放類的元數(shù)據(jù),例如類的實例實現(xiàn)了幾個方法履磨,具備多少個實例變量等信息刽宪。次結(jié)構(gòu)體的首個變量也是isa指針厘贼,這說明Class本身亦為Objctive-C對象。結(jié)構(gòu)體里還有個變量叫做super_class,它定義本類的超類圣拄,類對象所屬的類型(isa指針?biāo)赶虻念愋停┦橇硗庖粋€類,叫做元類,用來標(biāo)書類本身所具備的元數(shù)據(jù)则果。類方法就定義于此處棠赛,因為這些方法可以理解成類對象的實例方法,每個類僅有一個類對象饭耳,每個類對象僅有一個與之相關(guān)的元類串述。 (元數(shù)據(jù),就是這個類的數(shù)據(jù)哥攘。)
isKindOfClass:能夠判斷對象是否為某類或其派生類的實例
isMemberOfClass: 能夠判斷出對象是否為某個特定類的實例
15. 用前綴避免命名空間沖突
這個沒啥可說的
16. 提供全能初始化方法
這個沒啥可說的
17. 實現(xiàn)description方法
調(diào)試程序時經(jīng)常需要打印并查看對象信息剖煌。description 很實用。
Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property(nonatomic,assign)int age;
@property(nonatomic ,copy)NSString* name;
@end
Person.m
#import "Person.h"
@implementation Person
- (NSString *)description
{
return [NSString stringWithFormat:@"name %@ , age %d", self.name, self.age];
}
@end
description寫出想要的屬性逝淹, 在ViewController打印 Person 對象 Person的相關(guān)屬性就會出現(xiàn)在控制臺耕姊。
18. 盡量使用不可變對象
這個沒啥可說的
19. 使用清晰而協(xié)調(diào)的全名方式
這個沒啥可說的
20. 為私有方法名加前綴
這個沒啥可說的
21. 理解Objective-C錯誤模型
NSError的用法更加靈活,因此經(jīng)由此對象栅葡,我們可以把導(dǎo)致錯誤的原因匯報給調(diào)用者茉兰。
- NSError domain(錯誤范圍,其類型為字符串)
錯誤發(fā)生的范圍欣簇,也就是產(chǎn)生錯誤的根源规脸,通常用一個特有的全局變量來定義,比方說 “處理URL子系統(tǒng)”從URL的解析獲取數(shù)據(jù)時如果出錯了熊咽,那么就會使用NSURLErrorDomain來表示錯誤范圍 - Error code(錯誤碼莫鸭,其類型為整數(shù))
獨(dú)有的錯誤代碼,用以指明在某個范圍內(nèi)具體發(fā)生了何種錯誤横殴。某個特性范圍內(nèi)可能會發(fā)生一系列相關(guān)錯誤被因,這些錯誤情況通常采用enum來定義。例如,當(dāng)HTTP請求出錯時梨与,可能會把HTTP狀態(tài)碼設(shè)為錯誤碼 - User info(用戶信息堕花,其類型為字典)
有關(guān)錯誤的額外信息,其中或許包含一段“本地化的描述”或許還含有導(dǎo)致錯誤發(fā)生的另外一個錯誤粥鞋,經(jīng)由此種信息缘挽,可將相關(guān)錯誤串成一條“錯誤鏈”
@try {
NSString *str = @"wotaxiwa";
NSString *strErr = [str substringFromIndex:100];
NSLog(@"%@",str);
} @catch (NSException *exception) {
NSLog(@"ERROR: %@",exception);
} @finally {
NSLog(@"%s",__func__);
}
如果出現(xiàn)exception,異常后面的代碼將不會繼續(xù)執(zhí)行
22. 理解NSCopying協(xié)議
copy方法實際上是調(diào)用 -(id)copyWithZone:(NSZone*)zone; 實現(xiàn)copy操作呻粹, 如果想對自己的類支持拷貝并且做額外操作壕曼,那就要實現(xiàn)NSCopying協(xié)議此的方法。
為何出現(xiàn)NSZone呢尚猿,以前開發(fā)程序時窝稿,會據(jù)此把內(nèi)存分成不用的區(qū),而對象會創(chuàng)建在某個區(qū)凿掂。 現(xiàn)在不用了伴榔,每個程序只有一個區(qū):“默認(rèn)區(qū)”,所以不用擔(dān)心zone參數(shù)庄萎。
copy方法由NSObject實現(xiàn)踪少,該方法只是以默認(rèn)區(qū)為參數(shù)調(diào)用。mutableCopy方法實際上是調(diào)用 -(id)mutableCopyWithZone:(NSZone*)zone; 實現(xiàn)mutableCopy操作
copy mutableCopy 我認(rèn)為就是原型設(shè)計模式不明白的同學(xué)請看這個網(wǎng)頁
涉及到深拷貝和淺拷貝的知識不明白的同學(xué)請看這篇博客
23. 通過委托與數(shù)據(jù)協(xié)議進(jìn)行對象間通信
這一條說的就是delegate(代理設(shè)計模式)糠涛。但是并沒有說delegate的循環(huán)引用的問題,在使用代理聲明一個 @property的時候援奢,記得用weak。
@protocol PersonDelegate <NSObject>
-(void)areYouPerson;
@end
@property (nonatomic,weak)id<PersonDelegate> pd;
24. 將類的實現(xiàn)代碼分散到便于管理的數(shù)個分類之中
這個沒啥可說的
25. 總是為第三方類的分類名稱加前綴
這個沒啥可說的
26. 勿在分類中聲明屬性
正常的分類是不可以聲明屬性的忍捡,但是從技術(shù)上說集漾,分類里可以用runtime聲明屬性。
#import <objc.runtime.h>
static const char *kFriendsPropertyKey = “kFriendsPropertyKey”;
@implementation EOCPerson(Friendship)
-(NSArray*)friends{
return objc_getAssociatedObject(self,kFriendsPropertyKey);
}
-(void)setFriends:(NSArray*)friends{
objc_setAssociateObject(self.kFriendsPropertyKey,friends,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
這樣做可行砸脊,但是不太理想具篇,要吧相似的代碼寫很多遍。而且容易出現(xiàn)Bug凌埂,可以使用class-continuation實現(xiàn)分類添加屬性驱显。
27. 使用class-continuation分類隱藏實現(xiàn)細(xì)節(jié)
class-continuation分類和普通的分類不同,它必須在其所接續(xù)的那個類的實現(xiàn)文件里瞳抓。其重要之處在于埃疫,這是唯一能生命實例變量的分類,而且此分類沒有特定的實現(xiàn)文件孩哑,其中的方法應(yīng)該定義在類的主實現(xiàn)文件里栓霜。與其他分類不用,“class-continuation分類”沒有名字横蜒,比如叙淌,有個類叫做EOCPerson秤掌,其“class-continuation分類”寫法如下:
@interface EOCPerson()
@end
我們在創(chuàng)建一個類的時候系統(tǒng)已經(jīng)自動幫我們在,m中實現(xiàn)了愁铺,以下代碼都應(yīng)該很熟悉吧鹰霍。
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
沒錯它就是 class-continuation分類,在此代碼之間可以添加屬性茵乱,修改屬性茂洒。
@interface ViewController ()
@end
使用class-continuation分類的好處
- 可以向類中新增實例變量。
- 如果類中的主接口聲明為只讀瓶竭,可以再類內(nèi)部修改此屬性督勺。
- 把私有方法的原型文件生命在”class-continuation分類”里面。
- 想使類遵循的協(xié)議不為人知斤贰,可以用“class-continuation分類”中聲明智哀。
28. 通過協(xié)議提供匿名對象
這個沒啥可說的
說的就是這句話
@property (nonatomic,weak)id<PersonDelegate> pd;
29. 理解引用計數(shù)
理解引用計數(shù),方便于了解iOS的內(nèi)存管理荧恍。不過現(xiàn)在都是ARC的時代了瓷叫。
引用計數(shù)機(jī)制通過可以遞增遞減的計數(shù)器來管理內(nèi)存。對象創(chuàng)建好之后送巡,其保留計數(shù)至少為1摹菠。若保留計數(shù)為正,則對象繼續(xù)存活骗爆。當(dāng)保存計數(shù)降為0次氨,對象就被銷毀了。
在對象生命期中摘投,其余對象通過引用來保留或釋放此對象煮寡。保留與釋放操作分別會遞增及遞減保留計數(shù)。
30. 以ARC簡化引用計數(shù)
使用ARC要計數(shù)犀呼,引用計數(shù)實際上還是要執(zhí)行的幸撕,只不過保留與釋放操作現(xiàn)在由ARC自動為你添加。由于ARC會自動執(zhí)行retain圆凰、release杈帐、autorelease等操作,所以直接在ARC下調(diào)用這些內(nèi)存管理方法是非法的专钉。
ARC在調(diào)用這些方法時挑童,并不用過普通的Objective-C消息派發(fā)機(jī)制,二十直接調(diào)用其底層C語言版本跃须,這樣做性能更好站叼,直接調(diào)用底層函數(shù)節(jié)省很多CPU周期。
雖然有了ARC之后無需擔(dān)心內(nèi)存管理問題菇民,但是CoreFoundation對象不歸ARC管理尽楔,開發(fā)者必須適時調(diào)用CFRetain/CFRelease.
31. 在dealloc方法中只釋放引用并解除監(jiān)聽
當(dāng)一個對象銷毀的時候會調(diào)用dealloc方法投储,但是當(dāng)開銷較大或系統(tǒng)內(nèi)稀缺資源則不再此列,像是文件描述阔馋、套接字玛荞、大塊內(nèi)存等都屬于這種資源,通常對于開銷較大的資源實現(xiàn)一個方法呕寝,當(dāng)程序用完資源對象后勋眯,就調(diào)用此方法。這樣一來下梢,資源對象的生命期就變得明確了客蹋。
32.編寫“異常安全代碼”時留意內(nèi)存管理問題
圖不重要看字。
圖片中的情景是MRC∧踅現(xiàn)在已經(jīng)是ARC時代了讶坯。但是在使用@try 的時候也要注意,在捕獲到異常的時候@try{}中的語句執(zhí)行到異常代碼的那一行后不在執(zhí)行岗屏,然后把異常拋給@catch辆琅。當(dāng)然@finally是一定要執(zhí)行的。
如下 并沒有執(zhí)行代碼中的NSLog(@"%@",array);
@try {
NSArray *array = @[@"a",@"b",@"c"];
NSString *str_arr = array[4];
NSLog(@"%@",array);
} @catch (NSException *exception) {
NSLog(@"%@",exception);
} @finally {
NSLog(@"%s",__func__);
}
33. 以弱引用避免保留環(huán)
- unsafe_unretained 語義同assign等價担汤。然而assign通常用于int涎跨、float、結(jié)構(gòu)體等崭歧。unsafe_unretained多用于對象類型隅很。
- weak 與 unsafe_unretained 作用相同,然而只要系統(tǒng)把屬性回收率碾,屬性值為nil叔营。
推薦使用weak,畢竟是ARC時代的產(chǎn)物所宰,而且用的人也很多绒尊。
34. 以“自動釋放池塊”降低內(nèi)存峰值
@autoreleasepool {
<#statements#>
}
for (int i = 0; i < 1000000; i++) {
@autoreleasepool {
NSNumber *num = [NSNumber numberWithInt:i];
NSString *str = [NSString stringWithFormat:@"%d ", i];
[NSString stringWithFormat:@"%@%@", num, str];
if(lagerNum-1 == i)
{
NSLog(@"end");
}
}
}
由此可見我們合理運(yùn)用自動釋放池,可降低應(yīng)用程序的內(nèi)存峰值仔粥。
35. 用“僵尸對象"調(diào)試內(nèi)存管理問題
向已回收的對象發(fā)送消息是不安全的婴谱。
在左上角標(biāo)題欄找到項目單擊后選擇 Edit scheme 勾選圖中檢測僵尸對象
36. 不要使用retainCount
這個沒啥可說的
MRC時代的產(chǎn)物,忽略
37. 理解”塊“這一概念
這里其實就是在說block躯泰,復(fù)習(xí)一下block的語法吧
返回值類型(block名稱)(參數(shù))
需要注意的是 定義block時候谭羔,其所占內(nèi)存區(qū)域是分配在棧中的,快只在定義它的那個范圍內(nèi)有效麦向。block所使用的整個內(nèi)存區(qū)域瘟裸,在編譯期已經(jīng)完全確定,因此诵竭,全局block可以生命在全局內(nèi)存里话告,而不需要在每次用到的時候于棧中創(chuàng)建兼搏,另外,全局block的拷貝是個空操作沙郭,因為全局block絕不可能為系統(tǒng)所回收佛呻,這種block實際上相當(dāng)于單例。
38. 為常用的塊類型創(chuàng)建typedef
這個沒啥可說的
typedef <#returnType#>(^<#name#>)(<#arguments#>);
@property (nonatomic,copy)name nm_blk;
39. 用handler塊降低代碼分散程度
這條書上說的就是block的回調(diào)棠绘。只不過是把block放在方法中去使用件相。
// Person.h
#import <Foundation/Foundation.h>
typedef void(^Blk)(NSString *name,int age);
@interface Person : NSObject
-(void)handler:(Blk)blk;
@end
// Person.m
#import "Person.h
@implementation Person
-(void)handler:(Blk)blk{
if(blk){
blk(@"zhangsan" ,28);
}
}
@end
// 使用
Person *per =[Person new];
[per handler:^(NSString *name, int age) {
NSLog(@"%@ %d",name, age);
}];
這樣使用的好處是 在兩個對象通信的時候可以不使用delegate,方便了代碼的管理氧苍。其實這樣的用法很常見,多用于封裝網(wǎng)絡(luò)請求的基類泛范。
40. 用塊引用其所屬對象時不要出現(xiàn)保留環(huán)
這個沒啥可說的
41. 多用派發(fā)隊列让虐,少用同步鎖
派發(fā)隊列可用來表述同步語義,這種做法比使用@synchronize塊或NSLock對象更簡單
將同步與異步派發(fā)結(jié)合起來罢荡,可以實現(xiàn)與普通枷鎖機(jī)制一樣的同步行為赡突,而這么做卻不會阻塞執(zhí)行異步派發(fā)的線程
使用同步隊列及柵欄塊,可以令同步行為更加高效(不常用)
42. 多用GCD区赵,少用performSelector系列方法
這個沒啥可說的
43. 掌握GCD及操作隊列的適用時機(jī)
這個沒啥可說的
解決多線程與任務(wù)管理問題時惭缰,派發(fā)隊列并非唯一方案
操作隊列提供了一套高層的Objective-C API 能實現(xiàn)純GCD所具備的絕大部分功能,而且還完成一些更為復(fù)雜的操作笼才,那些操作弱改用GCD來實現(xiàn)漱受,則需另外編寫代碼。
使用NSOperation對線程管理
44. 通過Dispatch Group機(jī)制骡送,根據(jù)系統(tǒng)資源狀況來執(zhí)行任務(wù)
這個沒啥可說的
一系列任務(wù)可歸入一個dispatch group之中昂羡。開發(fā)者可以在這組任務(wù)執(zhí)行完畢時獲得通知
通過dispatch group,可以在并發(fā)式派發(fā)隊列里同時執(zhí)行多項任務(wù)摔踱。此時GCD會根據(jù)系統(tǒng)西苑狀況來調(diào)度這些并發(fā)執(zhí)行的任務(wù)虐先。開發(fā)者若自己來實現(xiàn)此功能。則需要便攜大量代碼派敷。
45. 使用dispatch_once來執(zhí)行秩序運(yùn)行一次的線程安全代碼
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
<#code to be executed once#>
});
46.不用使用dispatch_get_current_queue
這個沒啥可說的
iOS系統(tǒng)6.0版本起蛹批,已經(jīng)正式啟用此函數(shù)了
__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6,__MAC_10_9,__IPHONE_4_0,__IPHONE_6_0)
DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NOTHROW
dispatch_queue_t
dispatch_get_current_queue(void);
47.熟悉系統(tǒng)框架
打開Xcode command + shift + 0 選擇性的了解一些 Foundation、UIKit
也可以看看這篇博客 http://www.reibang.com/p/58bc11c800e4
48. 多用枚舉篮愉,少用for循環(huán)
因為枚舉遍歷的時候用的多線程(GCD并發(fā)執(zhí)行)腐芍,所以效率更快些。我覺得其實用什么都行潜支。
NSArray *arr = @[@"b",@"c",@"s"];
[arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
}];
49. 對自定義其內(nèi)存管理語義的collection使用無縫橋接
NSArray *anNSArray = @[@1,@3,@5,@8];
CFArrayRef acFArray = (__bridge CFArrayRef)anNSArray;
NSLog(@"%@",acFArray);
通過無縫橋接技術(shù)甸赃,可以在Foundation框架中Objective-C對象與CoreFoundation框架中的C語言數(shù)據(jù)結(jié)構(gòu)之間來回轉(zhuǎn)換。
在CoreFoundation層面穿件collection時冗酿,可以指定許多回調(diào)函數(shù)埠对,這些函數(shù)表示此collection應(yīng)如何處理其元素络断,然后可運(yùn)用無縫橋接技術(shù),將其轉(zhuǎn)換成具備特殊內(nèi)存管理語義的Objective-C collection项玛。
50. 構(gòu)建緩存時選用NSCache而非NSDictionary
NSCache勝過NSDictionary之處在于貌笨,當(dāng)系統(tǒng)資源耗盡時,它能自動刪減緩存襟沮。
51. 精簡Initialize與load的實現(xiàn)代碼
類初始化的時候一定會調(diào)用兩個方法
+(void)load{}
+ (void)initialize
{
if (self == [<#ClassName#> class]) {
<#statements#>
}
}
load方法只會調(diào)用一次锥惋,不管該類的頭文件有沒有被使用,該類都會被系統(tǒng)自動調(diào)用开伏,而且只調(diào)用一次膀跌。 當(dāng)然了,如果不重寫這個方法的話固灵,我們是不知道這個方法有沒有被調(diào)用的捅伤。
如果分類也重寫了load方法,先調(diào)用類里的巫玻,在調(diào)用分類丛忆。initialize 和load類似,不過在類被初始化的時候才會被調(diào)用(init之前)仍秤。需要注意的是熄诡,<#ClassName#>如果有子類繼承的時候要判斷類名。
52. 別忘了NSTimer會保留其目標(biāo)對象
// Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,strong)NSTimer *timer;
-(void)start;
-(void)stop;
@end
// Person.m
#import "Person.h"
@implementation Person
-(void)start{
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(run) userInfo:nil repeats:YES];
}
-(void)run{
NSLog(@"%s",__func__);
}
-(void)dealloc{
NSLog(@"%s",__func__);
}
-(void)stop{
[self.timer invalidate];
}
@end
調(diào)用
@property (nonatomic,strong)Person *person;
self.person = [Person new];
[self.person start];
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.person stop];
}
好诗力,那么問題來了凰浮,是不是沒有調(diào)用dealloc方法,沒有調(diào)用dealloc方法就說明Person對象并沒有被銷毀姜骡,為什么沒有被銷毀
因為在控制器強(qiáng)引用了self.person导坟,[self.person start]強(qiáng)引用了 self.timer; self.timer 的target指向了self(self.person)所以循環(huán)引用了。
怎么解決圈澈。 NSTimer銷毀的時候惫周,把Person對象為nil即可
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.person stop];
self.person = nil;
}