記一次線上'事故'處理
今早十點(diǎn)左右(2019年12月23日 10:00), 項(xiàng)目運(yùn)營反饋新版 App 有閃退問題侮繁,我放下手中開發(fā)工作古戴,開始排查問題所在:經(jīng)過查看崩潰日志發(fā)現(xiàn)隘击,已經(jīng)開始大面積影響線上用戶了
通過報(bào)錯(cuò)信息宋下,我很快確定了問題所在: 新版 App 和舊版本之間本地緩存的兼容問題,由于新版本緩存數(shù)據(jù)中緩存的鍵值對(duì)新增贰剥,導(dǎo)致對(duì)新 key 存取值報(bào)錯(cuò)弹沽。
具體原因
項(xiàng)目中網(wǎng)約車模塊由之前的「首汽約車」和「紅旗智行」兩個(gè)獨(dú)立的子項(xiàng)目合并成獨(dú)立的一個(gè)項(xiàng)目畴嘶。由于平臺(tái)的融合脆荷,項(xiàng)目中管理約車平臺(tái)和用戶類型的類有較大改動(dòng)凝垛。由之前的單平臺(tái)邏輯修改為現(xiàn)在多平臺(tái)邏輯。新邏輯如下:
新版本邏輯中將平臺(tái)信息和用戶類型信息同時(shí)保存到了一個(gè)字典中简烘,屬于字典套字典類型苔严,工具類統(tǒng)一管理頂層字典定枷」屡欤可以實(shí)現(xiàn)的功能為:用戶在 App 中平臺(tái)信息隨時(shí)切換,用戶類型信息隨時(shí)切換欠窒。約車過程中平臺(tái)信息也會(huì)隨著約車狀態(tài)變化覆旭。
突然想到,這里和 Runloop 中的 Mode 設(shè)置的邏輯很像岖妄,每個(gè)平臺(tái)下的各個(gè)用戶類型互不影響型将。對(duì)應(yīng)不同 Mode 下的源互不影響
原因
新版本中只判斷了 App 中是否有緩存,遺漏了緩存中沒有「sqhq」平臺(tái)的情況的適配荐虐。
只是判斷了有沒有緩存文件七兜,有緩存但是沒有「sqhq」平臺(tái)的情況沒有處理導(dǎo)致后面崩潰。
影響
1. 網(wǎng)約車整個(gè)模塊
2. 用戶退出 App.退出 App 會(huì)整體對(duì)平臺(tái)置為最基本的「sqhq」類型
處理方案
對(duì)于用戶:
卸載 App 重裝福扬,徹底清理緩存
對(duì)于開發(fā):
重寫緩存數(shù)據(jù)的處理腕铸,對(duì)于兼容問題引以為戒
下面是一些問題排查時(shí)候的記錄
設(shè)計(jì)原因
整個(gè)工具類,只提供了類方法處理平臺(tái)和用戶類型的存取铛碑。所以緩存文件也放到了類的初始化方法 + initialize
中狠裹。
關(guān)于 + initialize 和 + load 方法
load 方法
在類或者分類添加到 OC runtime 時(shí)候調(diào)用,可在此方法中設(shè)置類相關(guān)的行為
類的 load 方法在新類和新分類添加或鏈接的時(shí)候調(diào)用汽烦,其中的方法實(shí)現(xiàn)會(huì)根據(jù)最后一次的 load 而確定涛菠。類初始化順序如下
1. 先初始化自己鏈接的庫文件
2. 初始化自己類
3. 初始化項(xiàng)目中 C++ 和 __attribute__(constructor)
4. 初始化動(dòng)態(tài)鏈接自己的 frameworks
其中 load 方法的加載順序?yàn)椋簊uperClass -> subClass -> category.
所以在 load 階段不要調(diào)用其他類的方法,此時(shí)其他類的 load 可能還沒加載。
initialize 方法
即類的初始化方法俗冻,僅為類的初始化礁叔,執(zhí)行順序位于上面第三步。從方法在類的聲明周期內(nèi)只會(huì)執(zhí)行一次言疗,即分類和類本身只會(huì)執(zhí)行一次晴圾。如果做類或者分類的獨(dú)立處理,需要在 load 方法中噪奄。
此方法調(diào)用順序 superClass -> subClass
如果在子類調(diào)用中調(diào)用父類 initialize 可以通過 if (self == [ClassName self]) 來保護(hù)父類只執(zhí)行一次
經(jīng)驗(yàn)教訓(xùn)
- 對(duì)于向后兼容問題死姚,需要注意,在測試過程中需要引起注意
- 隨著用戶數(shù)增多勤篮,突然覺得自己的代碼變得更有意義了