閃退再現,沒有更新就沒有傷害
八月放到今年第一個颱風假
即使再怎麼喜歡上班
提早一天進周末假期
還是很不錯的
原本以為颱風過後
就會風平浪靜
沒想到出了一個前所未有的大包
當我在開新一期的工作單時
被PM緊急抓走
說是上版之後
大量用戶遇到閃退的狀況
不只客服接到一大堆電話
平常沒什麼人留言的Apple Store
也湧入巨量負評
更恐怖的是大螢幕上的Flurry紀錄
閃退率從不到1%
已超過80度角的斜率
直接暴衝到將近5、60%
差點以為工程師的生涯就要走到盡頭了…
傻眼歸傻眼
還是得解決問題
好險上一期有埋下上傳閃退紀錄的程式碼
所以可以在Flurry即時看到閃退的log
否則等到apple內建的crash log收到紀錄時
就為時已晚了
從Flurry下載閃退報告
發現是從未見過的例外:
NSKeyedunarchieve exception
原因是找不到相對應的.class檔案
回想一下上一期新增的功能中
唯一有可能和這個錯誤有相關的
只有改動info.plist裡面productName的屬性
一般來說不會去改productName
會去變更它的原因是
在做臉書登入時
臉書的SDK會吃到productName這個屬性
在彈窗顯示App的英文名稱
而非我們設定的facebookdisplayname
所以我就把productName從英文改為中文
臉書登入也就能顯示App的中文名稱了
但是單只這個改動
不太可能造成閃退
依照log找到閃退的行數
的確是閃退在NSKeyedUnarchiver這個方法
當初是為了在userDefault存取class
才會調用到NSKeyedArchiver和NSKeyedUnarchiver的方法
但是萬萬沒想到
Swift在將class進行Archive封裝時
會連帶把productName一起寫進去
(例如”MyApp.MyClass.swift”)
導致更換productName後
在Unarchiver時找不到這個class
就閃退了
要命的是
進入主畫面後
就馬上會讀取到這個userdefault
所以基本上用戶更新後
會是100%的閃退率
之前驗收沒有發現
是因為我們為了測試另外一個功能
會把app重新安裝
沒有發現這個問題
就送審出去了
知道問題後
直覺反應是先try catch起來
但是這個方法竟然沒有把例外拋出來
直接死在裡面
走投無路之際
還是仰賴Stack Overflow大神
查到解決之道
就是用setClassName這個方法
把之前封裝過的檔案名稱抓出來
強制重新命名
才解決這個問題
修復後速速重新上版
隔天送審過後
強制使用者進行版本更新
接著就看到閃退率
以-80度角急速下滑到不到1%
真的是沒踩過不會知道的坑
這個月還有一件事比較特別
就是請講師來講解單元測試
上課前要先看經典教材:
單元測試的藝術
裡面一句話說
不寫單元測試
嚴重的話就是提早結束工程師職涯
想到這一次的閃退問題
真的是心有戚戚焉
上課時老師提到幾個基本觀念
包括單元測試,整合測試,UITest的關係
簡單來說
單元測試單純測試程式邏輯
通常一次只測試一個case
不會有太複雜的邏輯
不可以依賴於外部的資料
包括檔案系統或是外部API
所以必須依賴fake, mock, 或是stub等物件
來達到隔離封閉的要求
而囊括和api界接或是檔案系統的測試
就是整合測試
最後才是針對畫面事件的UITest
好的測試程式碼
不外乎好閱讀,好維護,可信賴的
其實就和一般的程式碼的原則差不多
但是對於沒有寫過單元測試的我們來說
真的還滿困難的
再加上目前專案遇到的bug
有八成以上都是畫面上的問題
要進行UITest的部分
還得先寫好UnitTest和整合測試
只能說真的困難
講師也說這堂課的目的
是啟發我們「開始」寫測試
而非「教會」我們寫測試
看來測試的路上還有很長一條路要走啊
這個月還有一件大事
就是工作終於滿一年啦
想到剛進公司的前一個月
十點後離開公司總是家常便飯
(但是App還是一直Crash)
對比到現在工作都能如期完成
App也不會一天到晚閃退
(扣掉這次事件之外啦)
真的是感覺走了一段很遠的路
想當初在面試時
和主管說想要把手機寫好
雖然不敢說完美
但總算沒有辜負對自己的承諾
從新聞寫作到程式寫作
從面對人群到面對電腦
這一年工作的心路歷程
少了幾分人情世故的應對進退
多了幾分自我反省的耐心磨練
要感謝CMoney開設的戰鬥營
以及上課期間遇到的老師同學
還有工作後的同事主管
也謝謝一年半前的我
願意勇敢踏出這一步
才有今天的自己
附上工作滿一周年
公司送的機械式鍵盤
紅軸的清脆打字聲
寫code真的舒服
未來繼續加油!!