一宝穗、關(guān)于NSNull
先說(shuō)說(shuō)nil和NULL代表的是內(nèi)存中的一塊空地址,NSNull表示的是一個(gè)對(duì)象螺捐,指向一個(gè)nil地址颠悬。
文檔上這樣描述,NSNull一個(gè)單例定血,NSNull是一個(gè)用來(lái)表示不允許空值集合對(duì)象中的空值的赔癌。
其實(shí)NSNull存在的意義在于,OC中集合類型只能存儲(chǔ)對(duì)象不能存儲(chǔ)nil澜沟。存儲(chǔ)nil會(huì)報(bào)NSInvalidArgumentException灾票。可以用NSNull替代茫虽。
二铝条、self和super
在方法調(diào)用方面self表示調(diào)用自己的方法,super表示調(diào)用父類方法席噩。
self其實(shí)是類或者對(duì)象班缰,super是預(yù)編譯指令。
super調(diào)用的方法會(huì)轉(zhuǎn)換成如下指令:
//以class方法為例
[super class]
//runtime層
struct objc_super1 {
__unsafe_unretained id receiver;
Class superClass;
};
struct objc_super1 obj_super = {self,class_getSuperclass(object_getClass(self))};
id obj3 = objc_msgSendSuper(&obj_super,@selector(class));
可以看出super調(diào)用方法的時(shí)候會(huì)傳入當(dāng)前對(duì)象
三悼枢、保證屬性讀寫線程安全的方案
- 方案一:讀寫時(shí)加鎖可以實(shí)現(xiàn)需求埠忘,但這樣所有的屬性讀寫都是原子的,我們的需求是針對(duì)同一屬性線程安全馒索,所以這樣做效率較低莹妒。
- 方案二:可以創(chuàng)建一個(gè)串行隊(duì)列,把讀寫操作放到這個(gè)串行隊(duì)中同步執(zhí)行绰上,串行隊(duì)列的性質(zhì)可保證線程安全旨怠。優(yōu)化的話,可以將寫操作改為異步執(zhí)行蜈块,讀操作改為同步執(zhí)行鉴腻。這樣做的好處在于寫操作速度加快迷扇,不會(huì)阻塞主線程,但是究其根本所有的讀寫任務(wù)還是同步的爽哎,所以讀寫效率并不高蜓席。代碼如下:
- (void)setSomeString:(NSString *)someString{
dispatch_async(self.serialQueue, ^{
_someString = someString;
});
}
- (NSString *)someString{
__block NSString * localString;
dispatch_sync(self.serialQueue, ^{
localString = _someString;
})
return localString;
}
- 方案三:前面提到,讀取操作我們可以并行去做课锌,因?yàn)槊總€(gè)屬性互不干擾厨内,只要不與讀取操作同事執(zhí)行就可以,柵欄方法
dispatch_barrier_async
會(huì)在隊(duì)列中必須單獨(dú)執(zhí)行渺贤,一定不會(huì)與其他任務(wù)并發(fā)雏胃,利用這個(gè)特性,我可以更好的實(shí)現(xiàn)需求志鞍。代碼如下:
- (void)setSomeString:(NSString *)someString{
dispatch_barrier_async(self.syncQueue, ^{
_someString = someString;
})
}
- (NSString *)someString{
__block NSString * localString;
dispatch_sync(self.syncQueue, ^{
localString = _someString;
})
return localString;
}
以上代碼在不同線程讀取屬性的時(shí)候丑掺,可以并發(fā)讀取。同時(shí)又保證了讀取時(shí)的同步述雾。
- 擴(kuò)展,我們思考一下為什么不建議屬性用atomic關(guān)鍵字兼丰,大家都知道玻孟,其實(shí)atomic就是通過自旋鎖來(lái)保證讀寫線程安全的,這樣同一對(duì)象所有的屬性讀取都是同步的鳍征,而且會(huì)阻塞主線程黍翎,所以如果必須保證屬性的線程安全的話,推薦方案三艳丛。那么引申出來(lái)匣掸,如何保證兩類操作之間的線程安全呢?方案三是最好的選擇氮双。
四碰酝、GCD與NSOperation
GCD是純C的API,而NSOperation是面向?qū)ο蟮拇鞑睿珿CD是用塊這種輕量級(jí)的數(shù)據(jù)結(jié)構(gòu)來(lái)表示任務(wù)的送爸,而GCD則是用更加重量級(jí)的對(duì)象來(lái)表示的,NSOperation是基于GCD的那NSOperation的好處如下暖释。
- NSOperation可以通過cancel方法輕易的取消隊(duì)列中的任務(wù)袭厂,而GCD把塊安排到隊(duì)列中后是無(wú)法取消的。
- GCD可以輕易的設(shè)置依賴關(guān)系球匕,比如一個(gè)網(wǎng)絡(luò)操作需要之前的5個(gè)任務(wù)處理完畢之后才能進(jìn)行纹磺,我們可以將請(qǐng)求任務(wù)依賴于那五個(gè)任務(wù),這樣簡(jiǎn)單的可以實(shí)現(xiàn)需求亮曹,用GCD我們要用dispatch_group或者信號(hào)量的同步方式橄杨。
- 通過鍵值觀察可以了解到NSOperation的聲明周期秘症,比如屬性isCancel、isFinished等等讥珍。NSOperation適合進(jìn)行比GCD更加精密的操作历极。
- NSOperation可以執(zhí)行操作的優(yōu)先級(jí),隊(duì)列中優(yōu)先級(jí)高的任務(wù)先執(zhí)行衷佃,GCD則沒有直接操作優(yōu)先級(jí)的功能趟卸,只能操作隊(duì)列的優(yōu)先級(jí)。
- NSOperation對(duì)象內(nèi)置了很多方便的子類氏义,比如NSBlockOperation锄列。
五、用NSCache的幾點(diǎn)好處
- 低內(nèi)存時(shí)自動(dòng)刪減緩存惯悠,LRU(最近最少使用)緩存淘汰邻邮。
- 不同于NSDictionary,NSCache并不會(huì)拷貝鍵克婶,而是會(huì)保留鍵筒严,一些不支持拷貝的類也可以作為鍵。
- 可以設(shè)置最大開銷情萤,和數(shù)量鸭蛙,但這并不是對(duì)cache的硬限制,只做參考筋岛。
- NSCache可以配合NSPurgeableData使用娶视,當(dāng)NSPurgeableData對(duì)象被系統(tǒng)釋放的時(shí)候,緩存自動(dòng)清除睁宰。
六肪获、bounds和frame的區(qū)別?
- bounds:相對(duì)自身來(lái)說(shuō)的柒傻,控件的內(nèi)部尺寸孝赫,如果修改了Bounds,子控件的相對(duì)位置也會(huì)發(fā)生改變红符。
- Frame:相對(duì)于父控件來(lái)說(shuō)的寒锚,是控件的外部尺寸。
舉個(gè)例子:
let view = UIView(frame: CGRect.init(x: 100, y: 100, width: 100, height: 100));
view.backgroundColor = UIColor.red;
self.view.addSubview(view);
let subView = UIView(frame: CGRect.init(x: 20, y: 20, width: 60, height: 60));
subView.backgroundColor = UIColor.blue;
view.addSubview(subView);
print("viewFrame:\(view.frame) viewBounds:\(view.bounds) subViewFrame:\(subView.frame)");
view.transform = CGAffineTransform.init(scaleX: 2, y: 2);
print("viewFrame:\(view.frame) viewBounds:\(view.bounds) subViewFrame:\(subView.frame)");
//打印結(jié)果:
viewFrame:(100.0, 100.0, 100.0, 100.0) viewBounds:(0.0, 0.0, 100.0, 100.0) subViewFrame:(20.0, 20.0, 60.0, 60.0)
viewFrame:(50.0, 50.0, 200.0, 200.0) viewBounds:(0.0, 0.0, 100.0, 100.0) subViewFrame:(20.0, 20.0, 60.0, 60.0)
如上代碼給一個(gè)視圖放大而被违孝,發(fā)現(xiàn)其frame改變了刹前,因?yàn)殄^點(diǎn)默認(rèn)是中心,所以按中心放大雌桑,但是其bounds沒有改變喇喉,subView的frame也沒有改變。