完了蜒蕾!用完NSCache懷疑人生了....

在最近的一次項目模塊化實踐中稠炬,我重構(gòu)了Hybrid模塊的API分發(fā)機制。重構(gòu)中使用了NSCache咪啡,結(jié)果bug改到懷疑人生首启。

之前的hybrid模塊,API的實現(xiàn)與js-bridge耦合撤摸,業(yè)務(wù)使用時需要集中注冊API毅桃,由于部分UI接口需要依賴于宿主工程,對于模塊的各業(yè)務(wù)擴展性支持不好准夷≡糠桑基于此,本次重構(gòu)主要是針對hybrid的api分發(fā)機制衫嵌。

核心思想是读宙,通過api-manager來對api進行統(tǒng)一管理與分發(fā),全局維護一組api實例楔绞,api遵循api-protocol協(xié)議并在load中異步進行注冊结闸,webview根據(jù)group來標識一組api。

基于此酒朵,api-manger需要通過緩存來保存當前的api實例桦锄,確保app中所有的webview都可以使用,由于注冊可以使用異步注冊蔫耽,避免出現(xiàn)多線程問題结耀,這個地方的緩存采用了NSCache。

先還原一下現(xiàn)場:ApiManager是一個單例针肥,strong強引用了一個NSCache的實例,通過提供的宏異步注冊了api饼记,代碼大概長這樣:

@interface ApiManager ()
@property (nonatomic, strong) NSCache *cache;
@end
?
@implementation ApiManager
static id _instance;
+ (instancetype)manager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}
?
- (void)addObject:(id)object forKey:(NSString *)key {
    [self.cache setObject:object forKey:key];
}
?
- (id)objectForkey:(NSString *)key {
    return [self.cache objectForKey:key];
}
?
- (NSCache *)cache {
    if (_cache == nil) {
        _cache = [[NSCache alloc] init];
    }
    return _cache;
}
@end

當興高采烈的提測之后,噩夢開始了慰枕!提審前一天測試報了bug具则,APP打開了webview,進入后臺之后再次進入前臺,界面上的按鈕失效了具帮。

經(jīng)過確認博肋,cache緩存的ui-api注冊之后低斋,js端通過js-bridge給webview設(shè)置了一個原生按鈕并注冊了點擊事件。切換前后臺之后匪凡,點擊事件的target被置為了nil,導(dǎo)致無法響應(yīng)膊畴。

代碼大概是這樣的:


@interface UserInterfaceApi : NSObject

- (id)setNavigationBar:(id)parameter callback:(block)callback {
    ...
    if (leftItem != nil) {
        UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:image
                                                                       style:UIBarButtonItemStylePlain
                                                                      target:self
                                                                      action:@selector(actionLeft:)];
    }
    ...
}

- (void)actionLeft:(id)sender {
    ...
}

@end

唯一的原因是ui-api被釋放了,但在哪里釋放的呢病游?可能的原因有:

其他業(yè)務(wù)監(jiān)聽了前后臺事件唇跨,并同構(gòu)apimanager的接口移除了api

系統(tǒng)收到了內(nèi)存告警的通知,自動清除了cache

其他webview實例dealloc時clean了當前的api

搜索整個工程衬衬,監(jiān)聽前后臺事件的位置并沒有與api-manager交互买猖,切換前后臺時也沒有收到系統(tǒng)內(nèi)存告警。查了業(yè)務(wù)滋尉,并沒有其他webview主動釋放玉控,那問題出在哪里呢?

排除了上述三個原因之后狮惜,只能從cache這里入手了高诺。整個app運行期間,api僅僅被cache強引用碾篡,webview通過groupId來與api綁定時也是使用的弱引用虱而,所以只可能是NSCache出現(xiàn)了問題。

查閱官方文檔开泽,重新閱讀了一下這段話

The NSCache class incorporates various auto-eviction policies, which ensure that a cache doesn’t use too much of the system’s memory. If memory is needed by other applications, these policies remove some items from the cache, minimizing its memory footprint.

如果其他應(yīng)用需要內(nèi)存時薛窥,系統(tǒng)會將NSCache移除,也就是說系統(tǒng)會自己判斷在某個合適的時機清空cache眼姐。之前總以為系統(tǒng)內(nèi)存告警時會被移除,難道合適的時機還包括前后臺切換佩番?

于是众旗,將NSCahe換成了NSMutableDictionary試了一次,發(fā)現(xiàn)bug消失了趟畏」逼纾看來前后臺切換,系統(tǒng)確實會清理掉NSCache赋秀。

問題解決了利朵,那我們來重新總結(jié)一下NSCache。繼續(xù)翻看蘋果開發(fā)者文檔猎莲,我們發(fā)現(xiàn)NSCache有以下特點:

系統(tǒng)會在合適的時間清理掉NSCache

NSCache是線程安全的

key對象不會被拷貝绍弟,也即key無需遵循NSCopying協(xié)議

最后,NSCache使用時需要慎重考慮當前的業(yè)務(wù)環(huán)境著洼。

更多內(nèi)容歡迎關(guān)注我的公眾賬號樟遣,搜索“ smallyou_chmn” 查看更多精彩內(nèi)容

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末而叼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子豹悬,更是在濱河造成了極大的恐慌葵陵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞻佛,死亡現(xiàn)場離奇詭異脱篙,居然都是意外死亡,警方通過查閱死者的電腦和手機伤柄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門绊困,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人响迂,你說我怎么就攤上這事考抄。” “怎么了蔗彤?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵川梅,是天一觀的道長。 經(jīng)常有香客問我然遏,道長贫途,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任待侵,我火速辦了婚禮丢早,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秧倾。我一直安慰自己怨酝,他們只是感情好,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布那先。 她就那樣靜靜地躺著农猬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪售淡。 梳的紋絲不亂的頭發(fā)上斤葱,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音揖闸,去河邊找鬼揍堕。 笑死,一個胖子當著我的面吹牛汤纸,可吹牛的內(nèi)容都是我干的衩茸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蹲嚣,長吁一口氣:“原來是場噩夢啊……” “哼递瑰!你這毒婦竟也來了祟牲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤抖部,失蹤者是張志新(化名)和其女友劉穎说贝,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慎颗,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡乡恕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了俯萎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片傲宜。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖夫啊,靈堂內(nèi)的尸體忽然破棺而出函卒,到底是詐尸還是另有隱情,我是刑警寧澤撇眯,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布报嵌,位于F島的核電站,受9級特大地震影響熊榛,放射性物質(zhì)發(fā)生泄漏锚国。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一玄坦、第九天 我趴在偏房一處隱蔽的房頂上張望血筑。 院中可真熱鬧,春花似錦煎楣、人聲如沸豺总。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽园欣。三九已至,卻和暖如春休蟹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背日矫。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工赂弓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哪轿。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓盈魁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窃诉。 傳聞我的和親對象是個殘疾皇子杨耙,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355