iOS 學(xué)習(xí)知識(shí)點(diǎn)雜項(xiàng) 可能有錯(cuò)誤 學(xué)習(xí)還得靠自己
1. Category
Category(分類)主要作用是為已經(jīng)存在的類添加方法。Category 可以做到在既不子類化,也不侵入一個(gè)類的源碼的情況下,為原有的類添加新的方法,從而實(shí)現(xiàn)擴(kuò)展一個(gè)類或者分離一個(gè)類的目的。在日常開發(fā)中我們常常使用 Category 為已有的類擴(kuò)展功能。
雖然繼承也能為已有類增加新的方法,而且還能直接增加屬性,但繼承關(guān)系增加了不必要的代碼復(fù)雜度,在運(yùn)行時(shí),也無(wú)法與父類的原始方法進(jìn)行區(qū)分。所以我們可以優(yōu)先考慮使用自定義 Category。
通常 Category(分類)有以下幾種使用場(chǎng)景:
把類的不同實(shí)現(xiàn)方法分開到不同的文件里。
聲明私有方法。
模擬多繼承。
將 framework 私有方法公開化。
typedef struct category_t*Category;
structcategory_t{
constchar*name; // 類名
classref_tcls; // 類,在運(yùn)行時(shí)階段通過 clasee_name(類名)對(duì)應(yīng)到類對(duì)象
structmethod_list_t*instanceMethods; // Category 中所有添加的對(duì)象方法列表
structmethod_list_t*classMethods; // Category 中所有添加的類方法列表
structprotocol_list_t*protocols; // Category 中實(shí)現(xiàn)的所有協(xié)議列表
};
Category(分類)中的的方法、屬性、協(xié)議附加到類上的操作,是在 + load方法執(zhí)行之前進(jìn)行的。也就是說,在 + load方法執(zhí)行之前,類中就已經(jīng)加載了 Category(分類)中的的方法、屬性、協(xié)議。
而 Category(分類)和 Class(類)的 + load方法的調(diào)用順序規(guī)則如下所示:
先調(diào)用主類,按照編譯順序,順序地根據(jù)繼承關(guān)系由父類向子類調(diào)用;
調(diào)用完主類,再調(diào)用分類,按照編譯順序,依次調(diào)用;???
- load方法除非主動(dòng)調(diào)用,否則只會(huì)調(diào)用一次。
通過這樣的調(diào)用規(guī)則,我們可以知道:主類的 + load方法調(diào)用一定在分類 + load方法調(diào)用之前。但是分類 + load方法調(diào)用順序并不不是按照繼承關(guān)系調(diào)用的,而是依照編譯順序確定的,這也導(dǎo)致了 + load方法的調(diào)用順序并不一定確定。
2. Autoreleasepool所使用的數(shù)據(jù)結(jié)構(gòu)是什么?AutoreleasePoolPage結(jié)構(gòu)體了解么?
1. Autoreleasepool所使用的數(shù)據(jù)結(jié)構(gòu)是什么?
autoreleasepool 是沒有單獨(dú)的內(nèi)存結(jié)構(gòu)的,它是通過以AutoreleasePoolPage 為結(jié)點(diǎn)的雙向鏈表來實(shí)現(xiàn)的,當(dāng)調(diào)用[NSObject autorelease]時(shí)候,會(huì)在autorelease前面添加objc_autoreleasePoolPush(),在后面添加objc_autoreleasePoolPop()。
2. AutoreleasePoolPage結(jié)構(gòu)體
magic 用來校驗(yàn) AutoreleasePoolPage 的結(jié)構(gòu)是否完整;
next 指向最新添加的 autoreleased 對(duì)象的下一個(gè)位置,初始化時(shí)指向 begin() ;
thread 指向當(dāng)前線程;
parent 指向父結(jié)點(diǎn),第一個(gè)結(jié)點(diǎn)的 parent 值為 nil ;
child 指向子結(jié)點(diǎn),最后一個(gè)結(jié)點(diǎn)的 child 值為 nil ;
depth 代表深度,從 0 開始,往后遞增 1;
hiwat 代表 high water mark 。
另外,當(dāng) next == begin() 時(shí),表示 AutoreleasePoolPage 為空;當(dāng) next == end() 時(shí),表示 AutoreleasePoolPage 已滿。
3. 線程的autoreleasepool釋放時(shí)機(jī)。
autoreleasepool是在runloop結(jié)束或者休眠的時(shí)候釋放的。在runloop休眠的時(shí)候,會(huì)調(diào)用pop和push方法,先釋放舊的緩存池,再創(chuàng)建新的緩存池,在runloop結(jié)束的時(shí)候,直接pop緩存池,釋放對(duì)象。
而在push的時(shí)候會(huì)將release對(duì)象添加到autoreleasepoolpage中next指針指向位置,同時(shí)還添加一個(gè)哨兵POOL_SENTINEL標(biāo)記添加到緩存池的對(duì)象,當(dāng)pop的時(shí)候,會(huì)將next到哨兵POOL_SENTINEL的對(duì)象都釋放掉。
4. 自己添加的autoreleasepool釋放時(shí)機(jī)。
出了大括號(hào)就release。
3. 鎖
臨界區(qū):指的是一塊對(duì)公共資源進(jìn)行訪問的代碼,并非一種機(jī)制或是算法。
自旋鎖:是用于多線程同步的一種鎖,線程反復(fù)檢查鎖變量是否可用。由于線程在這一過程中保持執(zhí)行,因此是一種忙等待。一旦獲取了自旋鎖,線程會(huì)一直保持該鎖,直至顯式釋放自旋鎖。 自旋鎖避免了進(jìn)程上下文的調(diào)度開銷,因此對(duì)于線程只會(huì)阻塞很短時(shí)間的場(chǎng)合是有效的。
互斥鎖(Mutex):是一種用于多線程編程中,防止兩條線程同時(shí)對(duì)同一公共資源(比如全局變量)進(jìn)行讀寫的機(jī)制。該目的通過將代碼切片成一個(gè)一個(gè)的臨界區(qū)而達(dá)成。
讀寫鎖:是計(jì)算機(jī)程序的并發(fā)控制的一種同步機(jī)制,也稱“共享-互斥鎖”、多讀者-單寫者鎖) 用于解決多線程對(duì)公共資源讀寫問題。讀操作可并發(fā)重入,寫操作是互斥的。 讀寫鎖通常用互斥鎖、條件變量、信號(hào)量實(shí)現(xiàn)。
信號(hào)量(semaphore):是一種更高級(jí)的同步機(jī)制,互斥鎖可以說是semaphore在僅取值0/1時(shí)的特例。信號(hào)量可以有更多的取值空間,用來實(shí)現(xiàn)更加復(fù)雜的同步,而不單單是線程間互斥。
條件鎖:就是條件變量,當(dāng)進(jìn)程的某些資源要求不滿足時(shí)就進(jìn)入休眠,也就是鎖住了。當(dāng)資源被分配到了,條件鎖打開,進(jìn)程繼續(xù)運(yùn)行。
PS:
信號(hào)量(semaphore)
#ifndef WT_LOCK_CREATE
#define WT_LOCK_CREATE(lock) lock = dispatch_semaphore_create(1);
#endif
#ifndef WT_LOCK_LOCK
#define WT_LOCK_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#endif
#ifndef WT_LOCK_UNLOCK
#define WT_LOCK_UNLOCK(lock) dispatch_semaphore_signal(lock);
#endif
4. App啟動(dòng)過程
1:解析Info.plist
加載相關(guān)信息,例如如閃屏
沙箱建立、權(quán)限檢查
2:Mach-O加載
如果是胖二進(jìn)制文件,尋找合適當(dāng)前CPU類別的部分
加載所有依賴的Mach-O文件(遞歸調(diào)用Mach-O加載的方法)
定位內(nèi)部、外部指針引用,例如字符串、函數(shù)等
執(zhí)行聲明為attribute((constructor))的C函數(shù)
加載類擴(kuò)展(Category)中的方法
C++靜態(tài)對(duì)象加載、調(diào)用ObjC的 +load 函數(shù)
3:程序執(zhí)行
調(diào)用main()
調(diào)用UIApplicationMain()
調(diào)用applicationWillFinishLaunching
5. 無(wú)痕埋點(diǎn)
無(wú)痕埋點(diǎn)就是記錄所有的事件。
用戶點(diǎn)擊事件;
按鈕的點(diǎn)擊 UIApplication sendAction:to: from:forEvent:
手勢(shì)操作 UIGestureRecognizer initWithTarget:action: addTarget:action:
列表點(diǎn)擊 UITableView和UICollectionView setDelegate:、tableView:didSelectRowAtIndexPath:、 collectionView:didSelectItemAtIndexPath:等
系統(tǒng)彈窗 UIAlertView setDelegate:、alertView:clickedButtonAtIndex:
非點(diǎn)擊事件
頁(yè)面viewDidLoad 、viewWillAppear: 、viewDidAppear: 、viewWillDisappear
target:action:
6. iOS 常見設(shè)計(jì)模式
單例:UIApplication;
觀察者模式:KVO;
類簇:NSNumber;
裝飾者模式:分類;
命令模式:NSInvocation;
享元模式:UITableviewCell(UITableview的重用)
7. iOS 中內(nèi)省的幾個(gè)方法 class方法和objc_getClass方法有什么區(qū)別
判斷對(duì)象類型:
-(BOOL) isKindOfClass: 判斷是否是這個(gè)類或者這個(gè)類的子類的實(shí)例
-(BOOL) isMemberOfClass: 判斷是否是這個(gè)類的實(shí)例
判斷對(duì)象or類是否有這個(gè)方法
-(BOOL) respondsToSelector: 判讀實(shí)例是否有這樣方法
+(BOOL) instancesRespondToSelector: 判斷類是否有這個(gè)方法
object_getClass:獲得的是isa的指向
self.class:當(dāng)self是實(shí)例對(duì)象的時(shí)候,返回object_getClass。
類方法class,返回的是self,所以當(dāng)查找meta class時(shí),需要對(duì)類對(duì)象調(diào)用object_getClass方法
8. 反射
反射是指計(jì)算機(jī)程序在運(yùn)行時(shí)可以訪問、檢測(cè)和修改它本身狀態(tài)或行為的一種能力。
例如:
通過反射機(jī)制簡(jiǎn)單實(shí)現(xiàn)控制器跳轉(zhuǎn)
// SEL和字符串轉(zhuǎn)換
FOUNDATION_EXPORT NSString *NSStringFromSelector(SEL aSelector);
FOUNDATION_EXPORT SEL NSSelectorFromString(NSString *aSelectorName);
// Class和字符串轉(zhuǎn)換
FOUNDATION_EXPORT NSString *NSStringFromClass(Class aClass);
FOUNDATION_EXPORT Class __nullable NSClassFromString(NSString *aClassName);
// Protocol和字符串轉(zhuǎn)換
FOUNDATION_EXPORT NSString *NSStringFromProtocol(Protocol *proto);
FOUNDATION_EXPORT Protocol * __nullable NSProtocolFromString(NSString *namestr);
9. kvo和kvc
KVO
鍵值監(jiān)聽,是觀察者模式,用于監(jiān)聽屬性的改變,主要方法包括:
添加監(jiān)聽 - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
移除監(jiān)聽 - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context;
監(jiān)聽回調(diào) - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context;
原理
KVO 通過isa-swizzling(類型混合指針)機(jī)制來實(shí)現(xiàn),對(duì)象在被addObserver后,isa 指針指向了派生出的新類“NSKVONotifying_X元對(duì)象名X”,這個(gè)類繼承自原類,并重寫類被觀察對(duì)象的的 Set 方法(原對(duì)象必須有該屬性的 Set 方法),在新 Set 方法中添加了- (void)willChangeValueForKey:(NSString *)key;- (void)didChangeValueForKey:(NSString *)key;等方法以回調(diào)給觀察者。
手動(dòng)觸發(fā)回調(diào),則需要調(diào)用- (void)willChangeValueForKey:(NSString *)key;或- (void)didChangeValueForKey:(NSString *)key;
可以通過方法屏蔽某Key自動(dòng)生成的Set方法,而使用自己的Set方法觸發(fā)回調(diào)
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if ([key isEqualToString:@"name"]) {
return NO;
}else{
return [super automaticallyNotifiesObserversForKey:key];
}
}
-(void)setName:(NSString *)name{
if (_name!=name) {
[self willChangeValueForKey:@"name"];
_name=name;
[self didChangeValueForKey:@"name"];
}
}
? KVC
通過Key名直接訪問對(duì)象的屬性,或者給對(duì)象的屬性賦值.
(void)setValue:(nullable id)value forKey:(NSString *)key;
接受者會(huì)按照一定順序搜索設(shè)置屬性方法(搜索 setKey, _key, _isKey, key, isKey);
如果未找到設(shè)置方法,則會(huì)調(diào)用-setValue:forUndefinedKey:方法返回NSUndefinedKeyException異常;
如果找到方法,但是設(shè)置參數(shù)為 nil 或者類型不匹配,則會(huì)調(diào)用setNilValueForKey:方法并返回NSInvalidArgumentException異常。(nullable id)valueForKey:(NSString *)key;
接受者按照getKey:、key、isKey順序搜索獲取屬性值方法;
如果未找到方法,則調(diào)用+accessInstanceVariablesDirectly方法查看類是否允許按照_key, _isKey, key, isKey順序讀?。?br> 如果不允許或者最終未找到,則調(diào)用-valueForUndefinedKey方法,并返回NSUndefinedKeyException異常。
10. 關(guān)聯(lián)對(duì)象有什么應(yīng)用,系統(tǒng)如何管理關(guān)聯(lián)對(duì)象?其被釋放的時(shí)候需要手動(dòng)將所有的關(guān)聯(lián)對(duì)象的指針置空么?
可以不改變?cè)创a的情況下增加實(shí)例變量。
可與分類配合使用,為分類增加屬性.
AssociationsManager里面是由一個(gè)靜態(tài)AssociationsHashMap來存儲(chǔ)所有的關(guān)聯(lián)對(duì)象的。這相當(dāng)于把所有對(duì)象的關(guān)聯(lián)對(duì)象都存在一個(gè)全局map里面。而map的的key是這個(gè)對(duì)象的指針地址,而這個(gè)map的value又是另外一個(gè)AssociationsHashMap,里面保存了關(guān)聯(lián)對(duì)象的kv對(duì)。
銷毀
dealloc->rootDealloc->object_dispose->檢查有無(wú)關(guān)聯(lián)對(duì)象,有的話_object_remove_assocations刪除
11. weak原理
weak 對(duì)象弱引用
Runtime 維護(hù)了一個(gè)weak哈希表,用于存儲(chǔ)指向某個(gè)對(duì)象的所有weak指針,Key是所指對(duì)象的地址,Value是weak指針的地址數(shù)組。
階段:
1:objc_initWeak,初始化新的weak指針指向?qū)ο蟮牡刂贰?br>
2:objc_storeWeak,添加引用時(shí),更新指針指向,創(chuàng)建對(duì)應(yīng)的弱引用表。
3:clearDeallocating,根據(jù)對(duì)象地址獲取weak指針地址的數(shù)組,遍歷數(shù)組將其中的數(shù)據(jù)設(shè)為nil,將對(duì)象地址從weak表中刪除。
sideTables(64個(gè)元素長(zhǎng)度的hash數(shù)組)
sideTable->{
spinlock,
RefcountMap,(hash map,其key是obj的地址,而value,則是obj對(duì)象的引用計(jì)數(shù))
weak_table_t(以obj地址為key,弱引用obj的指針的地址作為value的hash表。hash表的節(jié)點(diǎn)類型是weak_entry_t)
}
struct weak_table_t {
weak_entry_t *weak_entries; // hash數(shù)組,用來存儲(chǔ)弱引用對(duì)象的相關(guān)信息weak_entry_t
size_t num_entries; // hash數(shù)組中的元素個(gè)數(shù)
uintptr_t mask; // hash數(shù)組長(zhǎng)度-1,會(huì)參與hash計(jì)算。(注意,這里是hash數(shù)組的長(zhǎng)度,而不是元素個(gè)數(shù)。比如,數(shù)組長(zhǎng)度可能是64,而元素個(gè)數(shù)僅存了2個(gè))
uintptr_t max_hash_displacement; // 可能會(huì)發(fā)生的hash沖突的最大次數(shù),用于判斷是否出現(xiàn)了邏輯錯(cuò)誤(hash表中的沖突次數(shù)絕不會(huì)超過改值)
};
12. atomic
atomic原子屬性
Set 方法:——reallySetProperty(…)
objc_retain(newValue);
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = newValue;
slotlock.unlock();
objc_release(oldValue);
Get 方法:——objc_getProperty(…)
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(oldValue);
slotlock.unlock();
return objc_autoreleaseReturnValue(value);
而其中
spinlock_t鎖實(shí)際為
using spinlock_t = mutex_tt;
而mutex_tt為
class mutex_tt : nocopy_t {
os_unfair_lock mLock;
}
其內(nèi)部是os_unfair_lock,iOS 10之后蘋果推薦使用os_unfair_lock來代替不在安全的OSSpinLock
Atomic 是否線程安全?
Atomic 并不能保證線程安全,它只能提升正確率,atomic只是在屬性的 Get/Set方法中賦值時(shí)添加了鎖;
A,B,C三個(gè)線程同時(shí)發(fā)起修改訪問屬性時(shí),并不能完全保證 A 線程寫后讀取到的值是 A 寫入的值,
也無(wú)法保證直接使用 _xxx方式 訪問實(shí)例變量,與使用 self. 的 Get/Set方法訪問屬性間獲得正確的值。
13. 消息轉(zhuǎn)發(fā)
1: 消息動(dòng)態(tài)解析
- (BOOL)resolveInstanceMethod:(SEL)sel;
- (BOOL)resolveClassMethod:(SEL)sel;
添加函數(shù)實(shí)現(xiàn)(配合class_addMethod())
2:消息接受者重定向
- (id)forwardingTargetForSelector:(SEL)aSelector;
返回新的接收者
3:消息重定向
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;
14. assign、retain、strong、weak、copy
assign:用于對(duì)基本數(shù)據(jù)類型進(jìn)行賦值操作,不更改引用計(jì)數(shù)
也可以用來修飾對(duì)象,但是,被assign修飾的對(duì)象在釋放后,指針的地址還是存在的,也就是說指針并沒有被置為nil,成為野指針。如果后續(xù)在分配對(duì)象到堆上的某塊內(nèi)存時(shí),正好分到這塊地址,程序就會(huì)crash。之所以可以修飾基本數(shù)據(jù)類型,因?yàn)榛緮?shù)據(jù)類型一般分配在棧上,棧的內(nèi)存會(huì)由系統(tǒng)自動(dòng)處理,不會(huì)造成野指針。
weak:修飾Object類型,修飾的對(duì)象在釋放后,指針地址會(huì)被置為nil,是一種弱引用。在ARC環(huán)境下,為避免循環(huán)引用,往往會(huì)把delegate屬性用weak修飾;在MRC下使用assign修飾。weak和strong不同的是:當(dāng)一個(gè)對(duì)象不再有strong類型的指針指向它的時(shí)候,它就會(huì)被釋放,即使還有weak型指針指向它,那么這些weak型指針也將被清除。
retain和strong:都是強(qiáng)引用,基本可以通用的。
在修飾block屬性的時(shí)候,相信大家都知道要用copy吧,因?yàn)槿绻籧opy的話,block是存放在棧連里面的,他的生命周期會(huì)隨著函數(shù)的結(jié)束而出棧的,copy之后會(huì)放在堆里面。
strong在修飾block的時(shí)候就相當(dāng)于copy,而retain修飾block的時(shí)候就相當(dāng)于assign,這樣block會(huì)出現(xiàn)提前被釋放掉的危險(xiǎn)。
copy:會(huì)在內(nèi)存里拷貝一份對(duì)象,兩個(gè)指針指向不同的內(nèi)存地址。一般用來修飾NSString等有對(duì)應(yīng)可變類型的對(duì)象,因?yàn)樗麄冇锌赡芎蛯?duì)應(yīng)的可變類型(NSMutableString)之間進(jìn)行賦值操作,為確保對(duì)象中的字符串不被修改 ,應(yīng)該在設(shè)置屬性是拷貝一份。而若用strong修飾,如果對(duì)象在外部被修改了,會(huì)影響到屬性。
PS:
block屬性為什么需要用copy來修飾?
因?yàn)樵贛RC下,block在創(chuàng)建的時(shí)候,它的內(nèi)存是分配在棧(stack)上的,而不是在堆(heap)上,可能被隨時(shí)回收。他本身的作于域是屬于創(chuàng)建時(shí)候的作用域,一旦在創(chuàng)建時(shí)候的作用域外面調(diào)用block將導(dǎo)致程序崩潰。通過copy可以把block拷貝(copy)到堆,保證block的聲明域外使用。在ARC下寫不寫都行,編譯器會(huì)自動(dòng)對(duì)block進(jìn)行copy操作。
__block與__weak的區(qū)別
__block:在ARC和MRC下都可用,可修飾對(duì)象,也可以修飾基本數(shù)據(jù)類型。
__block對(duì)象可以在block被重新賦值,__weak不可以。
__weak:只在ARC中使用,只能修飾對(duì)象,不能修飾基本數(shù)據(jù)類型(int、bool)。
同時(shí),在ARC下,要避免block出現(xiàn)循環(huán)引用,經(jīng)常會(huì):__weak typedof(self) weakSelf = self;
copy:
對(duì)象的復(fù)制就是復(fù)制?個(gè)對(duì)象作為副本,他會(huì)開辟?塊新的內(nèi)存(堆內(nèi)存)來存儲(chǔ)副本對(duì)象,就像復(fù)制?件?樣,即源對(duì)象和副本對(duì)象是兩塊不同的內(nèi)存區(qū)域。對(duì)象要具備復(fù)制功能,必須實(shí)現(xiàn)<NSCopying>
協(xié)議或者<NSMutableCopying>協(xié)議,常?的可復(fù)制對(duì)象有:
NSNumber、NSString、NSMutableString、NSArray、
NSMutableArray、NSDictionary、NSMutableDictionary
copy:產(chǎn)?對(duì)象的副本是不可變的
mutableCopy:產(chǎn)?的對(duì)象的副本是可變的
淺拷貝值復(fù)制對(duì)象本身,對(duì)象?的屬性、包含的對(duì)象不做復(fù)制
深拷?貝則既復(fù)制對(duì)象本身,對(duì)象的屬性也會(huì)復(fù)制?份Foundation中?持復(fù)制的類,默認(rèn)是淺復(fù)制對(duì)象的?定義拷?貝 對(duì)象擁有復(fù)制特性,須實(shí)現(xiàn)NSCopying,NSMutableCopying協(xié)議,實(shí)現(xiàn)該協(xié)議的CopyWithZone:?法或MutableCopyWithZone:?法。
淺拷?貝實(shí)現(xiàn)
-(id)copyWithZone:(NSZone *)zone{
Person *person = [[[self Class]allocWithZone:zone]init];
p.name = _name;
p.age = _age;
return person;
}
深拷?貝的實(shí)現(xiàn)
-(void)copyWithZone:(NSZone *)zone{
Person *person = [[[self Class]allocWithZone:zone]init];
person.name = [_name copy];
person.age = [_age copy];
return person;
}
深淺拷?貝和retain之間的關(guān)系
copy、mutableCopy和retain之間的關(guān)系
Foundation中可復(fù)制的對(duì)象,當(dāng)我們copy的是?個(gè)不可變的對(duì)象的時(shí)候,它的作?相當(dāng)與retain(cocoa做的內(nèi)存優(yōu)化)
當(dāng)我們使?mutableCopy的時(shí)候,?論源對(duì)象是否可變,副本是可變的
當(dāng)我們copy的 是?個(gè)可變對(duì)象時(shí),復(fù)本不可變
assign implies __unsafe_unretained ownership.
copy implies __strong ownership, as well as the usual behavior of copy semantics on the setter.
retain implies __strong ownership.
strong implies __strong ownership.
unsafe_unretained implies __unsafe_unretained ownership.
weak implies __weak ownership.
With the exception of weak, these modifiers are available in non-ARC modes.
15. 通知中心
同步操作
我在子線程發(fā)通知,接受者會(huì)在什么線程回調(diào)
main main : main
global main : global
main global : main
global global : global
不管消息接收者在什么線程addObserver,回調(diào)方法在發(fā)送消息線程執(zhí)行()
16. NSTimer
1. 底層實(shí)現(xiàn)原理
mk_timer
GCD timer
2. 循環(huán)引用
WeakProxy
GCD timer
3.注意事項(xiàng)
現(xiàn)成問題,RunLoop問題
void dispatch_create_timer(id target, double timeInterval, void (^handler)(dispatch_source_t timer))
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer =dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0, 0, queue);
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), (uint64_t)(timeInterval *NSEC_PER_SEC), 0);
__weak __typeof(target) weaktarget = target;
dispatch_source_set_event_handler(timer, ^{
if (!weaktarget) {
dispatch_source_cancel(timer);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
if (handler) handler(timer);
});
}
});
dispatch_resume(timer);
}
16. Tableview性能調(diào)優(yōu)
1. 減少 CPU 負(fù)荷,較少計(jì)算
cell的高度緩存
減少重新布局
減少使用storyboard,xib
2. 減少主線程占用時(shí)間
異步加載圖片
減少不必要的渲染
3. 預(yù)加載
在預(yù)加載方法中提前加載數(shù)據(jù),
圖片讀取時(shí),考慮到顯示區(qū)域可能遠(yuǎn)小于圖片大小,所以考慮使用
CGImageSourceCreateThumbnailAtIndex加載圖片