美團(tuán)Graver框架
1、將多個(gè)視圖層級渲染成一張bitmap
Method Swizzling
Swizzling should always be done in +load.
Swizzling should always be done in a dispatch_once.
每一個(gè)對象地址對應(yīng)一個(gè) ObjectAssociationMap 對象,而一個(gè) ObjectAssociationMap 對象保存著這個(gè)對象的若干個(gè)關(guān)聯(lián)記錄蓉坎。
- 關(guān)聯(lián)對象與被關(guān)聯(lián)對象本身的存儲并沒有直接的關(guān)系,它是存儲在單獨(dú)的哈希表中的;
- 關(guān)聯(lián)對象的五種關(guān)聯(lián)策略與屬性的限定符非常類似,在絕大多數(shù)情況下要销,我們都會使用OBJC_ASSOCIATION_RETAIN_NONATOMIC 的關(guān)聯(lián)策略,這可以保證我們持有關(guān)聯(lián)對象夏块;
- 關(guān)聯(lián)對象的釋放時(shí)機(jī)與移除時(shí)機(jī)并不總是一致疏咐,比如實(shí)驗(yàn)中用關(guān)聯(lián)策略 OBJC_ASSOCIATION_ASSIGN 進(jìn)行關(guān)聯(lián)的對象纤掸,很早就已經(jīng)被釋放了,但是并沒有被移除浑塞,而再使用這個(gè)關(guān)聯(lián)對象時(shí)就會造成 Crash 借跪。
- 無法很好的處理weak指針,通過OBJC_ASSOCIATION_ASSIGN酌壕,代表unsafe_unretain
Crash
1掏愁、crash原因
1) 野指針
- 原因
OC對象在釋放之后內(nèi)存空間可以被重新分配,在分配之前內(nèi)存數(shù)據(jù)還是存在的卵牍,這就是僵尸對象果港。OC對象釋放后,如果還存在指向該內(nèi)存的指針沒有設(shè)為nil糊昙,該指針就是野指針(wild pointer)辛掠。野指針還指指向未申請?jiān)L問受限的內(nèi)存空間 - 隨機(jī)性
當(dāng)Zombie Object所在的內(nèi)存還沒有被重新分配時(shí),通過野指針訪問是可以成功的释牺;但內(nèi)存已經(jīng)被重新分配萝衩,再用野指針訪問就會出錯(cuò)。 - 檢測
Xcode可以開啟Zombie Object檢測没咙,如果開啟猩谊,在每次訪問對象是都會檢測該對象是否是僵尸對象。當(dāng)一個(gè)對象被釋放后確保指針設(shè)為nil祭刚。 - 必現(xiàn)
通過scheme=>diagnostics=>Enable Scribble
設(shè)置牌捷,在釋放的對象所在的內(nèi)存填上不可訪問的數(shù)據(jù),這樣會引起objc_msgSend()
調(diào)用錯(cuò)誤袁梗,或者各種SIG錯(cuò)誤宜鸯。
也可以通過hook NSObject的dealloc,runtime obj_dispose遮怜, c的free來在對象釋放時(shí)向所在內(nèi)存寫入數(shù)據(jù)。
Notifications
1 why notification
notification實(shí)現(xiàn)了一對多的通知機(jī)制鸿市,通知的接受者(observer)和發(fā)送者(sender)互不了解锯梁,從而實(shí)現(xiàn)解耦
2 線程安全
Notification的post線程與observer的接收回調(diào)在同一個(gè)線程中。如果要修改接收回調(diào)的線程有兩種方案
- 使用 NSPort轉(zhuǎn)發(fā)焰情。
- 使用 block API指定block執(zhí)行的queue
3 線程同步性
postNotification:總是會卡住當(dāng)前線程陌凳,待observer執(zhí)行(如不特殊處理selector也會在postNotification:所在線程執(zhí)行)結(jié)束之后才會繼續(xù)往下執(zhí)行。
4 異步通知
將NSNotification放入NSNotificationQueue内舟,然后根據(jù)其type合敦,NSNotificationQueue在合適的時(shí)機(jī)將其post到NSNotificationCenter。這樣就完成了異步的需求验游。還可以使用queue進(jìn)行notification合并
typedef NS_ENUM(NSUInteger, NSPostingStyle) {
NSPostWhenIdle = 1, // 當(dāng)runloop處于空閑狀態(tài)時(shí)post
NSPostASAP = 2, // 當(dāng)當(dāng)前runloop完成之后立即post
NSPostNow = 3 // 立即post充岛,同步會阻塞post線程
};
typedef NS_OPTIONS(NSUInteger, NSNotificationCoalescing) {
NSNotificationNoCoalescing = 0, // 不合成
NSNotificationCoalescingOnName = 1, // 根據(jù)NSNotification的name字段進(jìn)行合成
NSNotificationCoalescingOnSender = 2 // 根據(jù)NSNotification的object字段進(jìn)行合成
};
// 方式1:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
A *a = [A new];
[a test];
self.a = a;
NSNotification *noti = [NSNotification notificationWithName:@"111" object:nil];
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostASAP coalesceMask:NSNotificationNoCoalescing forModes:nil];
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing forModes:nil];
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostNow coalesceMask:NSNotificationNoCoalescing forModes:nil];
NSLog(@"測試同步還是異步");
return YES;
}
// 方式2:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
A *a = [A new];
[a test];
self.a = a;
NSNotification *noti = [NSNotification notificationWithName:@"111" object:nil];
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostASAP coalesceMask:NSNotificationCoalescingOnName forModes:nil];
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostNow coalesceMask:NSNotificationCoalescingOnName forModes:nil];
NSLog(@"測試同步還是異步");
return YES;
}
result:
// 方式一
2017-02-26 20:09:31.834 notification[20612:12733161] selector 1
2017-02-26 20:09:31.835 notification[20612:12733161] block 2
2017-02-26 20:09:31.835 notification[20612:12733161] 測試同步還是異步
2017-02-26 20:09:31.851 notification[20612:12733161] selector 3
2017-02-26 20:09:31.851 notification[20612:12733161] block 4
2017-02-26 20:09:31.854 notification[20612:12733161] selector 5
2017-02-26 20:09:31.855 notification[20612:12733161] block 6
// 方式二
2017-02-26 20:11:31.186 notification[20834:12736113] selector 1
2017-02-26 20:11:31.186 notification[20834:12736113] block 2
2017-02-26 20:11:31.186 notification[20834:12736113] 測試同步還是異步
5 dealloc remove
iOS8及以前保檐,NSNotificationCenter持有的是觀察者的unsafe_unretained指針(可能是為了兼容老版本),這樣崔梗,在觀察者回收的時(shí)候未removeOberser夜只,而后再進(jìn)行post操作,則會向一段被回收的區(qū)域發(fā)送消息蒜魄,所以出現(xiàn)野指針crash扔亥。而iOS9以后,unsafe_unretained改成了weak指針谈为,即使dealloc的時(shí)候未removeOberser旅挤,再進(jìn)行post操作,則會向nil發(fā)送消息伞鲫,所以沒有任何問題粘茄。
RAC
FRP
FR
Functional programming is a programming paradigm?—?a style of building the structure and elements of computer programs?—?that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data?—?Wikipedia
簡單來講FR是一種用數(shù)學(xué)函數(shù)的方法實(shí)現(xiàn)無side effect的編程范式。Concept
- Pure functions:同樣的輸出同樣的輸出榔昔,不產(chǎn)生side effect
文件操作通常不是pure的驹闰,因?yàn)槲募梢员桓淖?br> pure很容易通過測試 - Immutability:不改變值或狀態(tài)
循環(huán)里會有值或狀態(tài)的改變,可以用遞歸函數(shù)避免
鏈?zhǔn)秸{(diào)用可以避免出現(xiàn)中間可變狀態(tài)撒会,一個(gè)輸入經(jīng)過多次處理產(chǎn)生一個(gè)輸出 - Referential transparency
pure functions + immutable data = referential transparency
一個(gè)函數(shù)的輸入不變時(shí)嘹朗,函數(shù)的輸出也不變,所以對于同一個(gè)input可以直接用output來替代函數(shù)調(diào)用诵肛,這樣可以優(yōu)化程序性能屹培,這種技術(shù)叫Memoization。 - Functions as first-class entities
可以被變量引用
可以作為參數(shù)傳遞
可以作為函數(shù)輸出 - Higher-order functions (以函數(shù)作為參數(shù)或返回一個(gè)函數(shù))
在處理序列時(shí)通常通過循環(huán)來一個(gè)個(gè)處理序列中的元素(Imperative approach)怔檩,使用高階函數(shù)可以像自然語言表達(dá)一樣處理序列(Declarative approach)褪秀。這種方式隱藏了實(shí)現(xiàn)過程,只關(guān)注具體事務(wù)薛训。 - reference: Functional Programming Principles in Javascript
- Functors, Applicatives, And Monads
reference: Functors, Applicatives, And Monads In Pictures
- Reactive Programming
- 響應(yīng)式編程是一種關(guān)注于數(shù)據(jù)流和數(shù)據(jù)傳播變化的聲明式編程范式(Reactive programming - wiki)媒吗,這種范式可以優(yōu)雅的表達(dá)靜態(tài)(eg array)和動態(tài)( event emitters)數(shù)據(jù)流。
- declarative programming只關(guān)注于邏輯表達(dá)乙埃,隱藏了實(shí)現(xiàn)過程闸英。imperative programming會把所有的實(shí)現(xiàn)指令表達(dá)出來。declarative方便于面向?qū)ο蠼橥啵憫?yīng)式開發(fā)等開發(fā)甫何;imperative方便于算法開發(fā)。
-
FRP
cold/hot signal
- Hot Observable是主動的遇伞,盡管你并沒有訂閱事件辙喂,但是它會時(shí)刻推送,就像鼠標(biāo)移動;而Cold Observable是被動的巍耗,只有當(dāng)你訂閱的時(shí)候秋麸,它才會發(fā)布消息。
- Hot Observable可以有多個(gè)訂閱者芍锦,是一對多竹勉,集合可以與訂閱者共享信息;而Cold Observable只能一對一娄琉,當(dāng)有不同的訂閱者次乓,消息是重新完整發(fā)送。
- RACSubject及其子類是熱信號, RACSignal排除RACSubject類以外的是冷信號孽水。
memgraph
移動平臺
1票腰、小程序解決了H5容器以下缺點(diǎn)
- 安全:不允許直接操作dom
- 性能:H5最終由webview渲染,小程序可以native也可以其他方式渲染
- 開發(fā)效率
load & initialize
啟動優(yōu)化
pre-main階段優(yōu)化
- 刪除無用代碼
- 抽象重復(fù)代碼
- +load方法中做的事情延遲到+initialize中女气,或者在+load中做的事情不宜花費(fèi)過多時(shí)間
- 減少不必要的framework杏慰,或者優(yōu)化已有的framework