你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 如何接手一個老舊的iOS項目

如何接手一個老舊的iOS項目

編輯:IOS開發基礎

57.jpg

作者:點燃那火焰

續命

一個程序員最氣憤的事是什麼?沒有文檔!

一個程序員最討厭的事是什麼?寫文檔!

以上被稱為“程序員的糾結”,Unbelievable!最近我就趕上這麼糾結的事了,公司有一個項目,姑且稱之為“起死回生項目”吧,成立於兩年前,當時已經上架,但效果不好,又被迫下架關項目,但是人生就是這麼奇妙,兩年後時來運轉,市場迫切需要的東西正是這個“起死回生項目”,於是它+1s,咳咳,不,是起死回生了,然而當時所有的項目組成員均已離職,沒有文檔!沒有人交接!

誰來接手呢?領導說交給我,筆者當時正在另一個項目組上,當時我就說我一個其他項目組的,怎麼能去起死回生項目組呢,領導對我說:“組織上已經決定了,由你來當總書。。。咳咳,由你來重啟這個項目”。我心中無限感慨,當時就念了兩句詩:“苟利國家生死以。。。咳咳”

於是我就來到了這個坑爹的項目組,哦,對了該項目組只有我一個人!

而此時的我,剛剛學會iOS一年。。。。。

面臨的問題

作為一個有責任有擔當的新世界好青年,組織既然已經決定了,我又是黨員,這時候我不上誰上呢?!帶著這樣的決心,我開始了奇妙的重啟之旅。

首先,獲得帶權限,從服務器上下載來代碼,發現項目竟然運行不起來!?

一大堆Warning、Error!!

what!?

不是說已經上線了嗎?我看了下提交日志,最後一條是修改build號,發布到App Store了,怎麼會跑不起來呢?

仔細再看報錯,大多數是缺少文件類的,就是缺少framework、第三方庫之類的,但是奇怪的是之前確實可以跑得啊,於是通過N層關系找到原來的項目組成員,是的,在電話中得知,這個項目的依賴庫管理當時采用的是靜態庫方法,如今的小伙伴用cocoapods用的飛起,一句pod update搞定所有,然而當年,我不知道cocoapods發布了沒有,至少這個項目沒有采用,那麼如何管理眾多的第三方庫和組件呢?

答案是另起一個項目,把所需組件和庫,編譯成一個CommonLib Frameworks,再在主項目中導入framework。如今網上還能找到怎麼制作framework的文檔,不再贅述,大家找吧。

如下圖,這是我已經導入了一部分的截圖

01.png

缺少的Framework

原來是沒有導入Framework,才會出現的error,知道原因就好辦,我又找到這個Framework的代碼,加入進來,果然OK了,至此,我們終於build success。

同時也發現,該項目當時支持的最低版本是iOS 6.1,嗯,是的,在iOS 10.2發布的時候,這個項目還停留在6.1

2.png

最低支持版本

撸起袖子,加油干

好了,吐槽完了,該干的還得干呢,於是我開始思考,如何接收這樣的項目呢?

上干貨!

3.png

升級遷移計劃

以上是我的思維導圖,當然是邊做邊補充的,就像阿甘說的,你永遠不知道下一個坑在哪裡,走一步看一步了

下面就按照思維導圖的順序來做一一介紹!

1.遷移到Cocoapod

1.1 問題

  • 依賴庫不易管理,自己人肉的方式管理依賴庫的痛苦大家都懂,這也是cocoapods盛行的原因

  • 沒有版本管理,你只能去打開工程,肉眼分辨當時用的是哪個版本,例如MJRefresh已經更新到3.0,而項目中的是什麼版本呢,不知道

解決方法當然就是如標題所說,遷移到Cocoapod

1.2 遷移

思維導圖上,可以看到我面臨的問題

  • 依賴庫統計

我必須知道項目中使用到了哪些第三方庫,哪些有Cocoapods版本,哪些沒有,這部分,我采用的本辦法,打開這個工程,人肉統計,有下圖這麼多!!!

 

4.png

依賴庫

呵呵!

沒辦法,只能去這麼做,這時候我們又發現,這麼多第三方庫,有些是沒有用到的,如何發現?就是去全局搜索咯

我猜是某些組件不再用了,但是沒有及時清理,於是留給後人很多無用代碼,也提醒讀者,注意這一點,不要害人害己啊

最終清理後的組件,不如上圖這麼多,大概二十個左右,整理成一個podfile文件,如下

注意,這裡每個組件名後,都有指定版本號,在下一節切換中有提到,如何確定版本號

5.png

podfile

這部分用到最多的就是cocoapods的搜索功能

pod search AFNetworking 

  • 切換

現在准備工作完畢,就是要切換了!

首先,需要去除工程配置文件裡面的很多配置項,原則就是靜態庫需要配置上的,這裡都得刪除,目標是把就項目中的所有相關CommonLibARC的配置清理干淨

例如下面的,配置很多很雜我這裡就不一一截圖,僅上圖2張供參考

6.png

圖1

7.png

圖2

然後,就是Cocoapods的部分了,網絡上有大量教程,我們需要建立podfile,再用pod install命令。這樣會生成一個xcworkspace文件,以後需要從這裡打開工程,如下圖,所有第三方組件被管理在Pods工程下

8.png

目錄

於此同時,這時也會產生大量的error,原因是podfile中需要制定庫的版本,而我們並不知道兩年前使用的什麼版本,隨著版本的變化,方法名可能會變動,甚至被干掉,這樣build必然失敗。

我的方法是:

1.用pod search,看看組件有哪些版本,先選一個比較穩定的大版本,比如,MJRefresh最新是3.1.12,從版本號和時間推算,當時工程中肯定是特別老的,可能是1.x,但是考慮到時間推移,組件也是有必要的升級,我最終選擇了3.0版本,這個版本使用者多,且並不算太老舊

9.png

pod search

果然產生大量方法名變動,沒轍,自己人肉一一修改,舉例如下

10.png

MJRefresh 方法名變動

2. error層出不窮

我進行到這一步是最痛苦的,因為連續幾天都是無法編譯成功的,因為當編譯器遇到一些error後就不在往下編譯了,因此你看到比如3個error,解決了他們,再build,發現又多出來5個,這種更多是精神上的折磨,耐性的消磨。而且我沒法提交代碼,因為每次我只解決了一部分問題,只能先暫存到本地,到編譯成功了才能正式提交到remote。

3. CocoaLumberjack--->DDLog

這裡特別要提一下CocoaLumberjack,這是一個集快捷、簡單、強大和靈活於一身的日志框架,我們主要用到的是DDlog,這是項目原本就在用的組件,但是DDlog需要定義一個日志級別,低於這個級別的log不再顯示。

在源代碼中,是每個用到的地方都在.m文件都定義一次,全局搜索會發現很多同樣的代碼, 顯得啰嗦

11.png

很多重復定義

12.png

定義日志級別

因此,我將其改到了PCH文件中,在appdelegate中定義其級別,這樣只需一次,全局通用

4. Crashlytics

這裡多提一次Crashlytics,這是個非常好用的統計Crash的工具,植入方便,使用簡潔,5分鐘搞定,強烈安利一發。原項目也有使用,不過賬號密碼沒有移交下來,我乘此機會將其更新到了最新版本

好了,至此,所有的遷移工作已經完成,我興奮的按下Command+B,Build Success!!!

然而茫茫多的warning還沒有解決呢

5. 組件過渡方法

有部分組件,牽扯范圍廣,替換起來特別麻煩,為了不影響進度此時我決定,先跑起來,後面再慢慢優化,於是,采用的了過渡方法,先不用cocoapod管理,但是Framework必須刪除,否則又會有沖突,怎麼辦呢

簡單粗暴的拖拽,直接把組件文件夾add進project!

先跑起來再說啊!

2 iOS 8.0 升級

13.png

 最低版本

此時的項目,歷經歲月的滄桑,他終於跑起來了,但是項目依然停留在歷史的那個時刻,iOS 6.1!!!!

然後,我們再到蘋果官網,查看各版本占比,如圖,截止2017.01.04號,額,已經看不到8以下的,加一塊才6%

14.png

iOS版本占比

於是,我又開始了新的征程,升級到iOS 8.0,為啥是8.0呢?

步子大了怕扯到蛋!

如最上面的思維導圖所示,warning大部分集中在以下幾個地方

2.1  Method Deprecation

蘋果也是個坑爹的公司,隨著iOS版本的升級,需要系統原生的類和方法都發生了變化,有了新的方法替代,系統會提示我們改掉,又是個苦力活,沒辦法一一去改吧,此項目中碰到最多的是,UILabel的方法,用於計算字體大小

16.png

deprecated warning

17.png

deprecated warning

2.2 Format String Issue

這類比較好解決,大多數是系統可以幫忙解決,相信你們一定碰到過

 18.png

Format String Issue

2.3 Conflicting Return Type

這個和第一種類似,都系統方法升級導致的,依照提示改過來即可

19.png

Conflicting Return Type

2.4 missing [super awakeFromNib]

這是坑爹的代碼風格導致,所有的UITableViewCell都沒有[super awakeFromNib]方法。

大家知道,我們在工程實踐中有RootClass,比如RootTableViewCell,所有cell都繼承於RootClass,在RootClass實現一些基本的、全局的屬性和方法,通常我們寫的就是awakeFromNib方法,缺失這個方法使得所有子類沒有繼承到父類的全局設置。

沒二話,必須加上

20.png

missing [super awakeFromNib]

21.png

missing [super awakeFromNib]

2.5 ARC bug

這個Bug估計是手抖寫錯了,但是排查起來挺麻煩的。

現象是某個頁面在debug的時候正常,但是打包安裝到手機上就會閃退,由於調試時一直是好的,所以抓不到Crash,這時候就是Crashlytics大顯身手的時候,我們登錄Crashlytics的網站,可以清楚的看到崩潰日志,如下圖,這裡顯示崩潰的原因是unrecognized selector,也就說一個對象調用了未知方法,按照Log指示,其實是一個NSDictionary調用了 objectAtIndex:方法

26.png

Crashlytics崩潰日志

再仔細看下去其實日志中還有具體crash的行數在305行,這行代碼如下:

27.png

代碼

確實是調用了objectAtIndex方法,可是這個yLabelsStringArray確實是一個NSArray啊!怎麼會變成NSDictionary了呢?錯在哪裡呢

28.png

數組屬性

仔細看的同學會發現,這個屬性的ARC參數是assign,大家知道assign是用於非指針變量,用於基礎數據類型,並不會對引用計數+1,也就說這個NSArray被創建後,就立馬被釋放了,這才導致崩潰,如此只有改成strong即可

 29.png

改成strong

至此,整個項目build success!!

3 增加Log

好了,我們已經將一個老舊的iOS工程,成功升級成最常用的工程,但是迄今我們甚至沒有去了解整個項目是干嘛的,也就是說我們根本沒有了解到業務邏輯,由於文檔缺失,如何掌握業務邏輯成了大麻煩,我們只能通過自己把玩這個App,每個頁面去點點,去操作。於是為了方便快速掌握代碼架構和業務了解,需要Log來幫助我們理解項目

而原工程幾乎沒有任何Log。。。。

3.1 ViewWillAppeared/ViewdidLoad

所幸的是,這個工程的所有的ViewController都是繼承於一個RootController,於是在BaseViewController中,加入log,這我們在Debug時,隨著操作,我們就能知道哪個頁面對應哪個ViewController,這裡就用到了上面提到的DDLog

#ifdef DEBUG

DDLogInfo(@"%@ viewDidLoad", [self class]);

#endif
#ifdef DEBUG

DDLogInfo(@"%@ viewWillAppear", [self class]);

#endif

37.png

3.2 Network Request Log

同樣的,我們對於接口調用也是一無所知,必須在網絡也打上Log,為了方便調試,我打印出了URL、Method(GET/POST)、參數、Header

多提一句為啥打印出Header,因為Header中有access token,這樣我們可以使用Postman來做需要登錄的接口調試,而不必在app點擊來觸發請求

38.png

Network Log

同樣的,安利一下Postman,非常好用的網絡調試工具

30.png

Postman

3.3 DB file path

工程中還有數據庫,在用模擬器調試的時候,其實我們是可以打開運行中App的數據庫的,只需打印出database的文件路徑即可,方便我們未來的調試

4 無效代碼移除

Log完成後,我們可以安心的來整理業務邏輯了。

跟需求方溝通後,app中有些功能完全可以移除掉了,接下來就是刪代碼的節奏了

這部分比較簡單,無用代碼找出來,Delete即可,還是苦力活

5 工程整理

5.1 模塊化目錄

工程中的目錄結構也是一個需要注意的地方,我采用的是使用最廣泛的MVC結構

 40.png

目錄結構

5.2 網絡層整理

工程采用的是最常見的AFNetworking,這部分依然是體力活

  • 首先需要整理出服務器地址,包括Dev(開發)、Stg(上線)、Pro(生產)三個環境

  • 需要整理出所有的接口文檔,這就是靠Network Log了

  • 網絡層邏輯整理,需要閱讀代碼,理解原本是怎麼構建出網絡層的,這部分可以暫放一會

5.3 數據庫整理

項目的許多數據是存在數據庫裡面的,從依賴庫來看,使用的是FMDB,也是比較常見的開源庫

我使用的是MesaSQLite作為client

這部分工作,需要有人配合,暫時放一放

6 storyboard臃腫

原項目中,所以的ViewController,注意,是所有的ViewController都在一個storyboard裡,所以當你想打開這個storyboard時,需要等,嗯,大約3min,給大家看一看,注意最下面我已經縮放到6.25%了,這樣一個龐大、臃腫的storyboard,即不好管理,也不會擴展,打開它還有嚴重的卡頓

71.png

storyboard

這部分我暫時寫一下思路,因為還沒有實施

6.1 方案一:storyboard reference

為了解決這個問題,在 iOS 9 中蘋果介紹了 Storyboard References 這個概念。Storyboard References 允許你從 segue 中引用其他 storyboard 中的 viewController。這意味中你可以保持不同功能模塊化,同時 Storyboard 的體積變小並易與管理。不僅容易理解了,和團隊一起工作時,合並(工作成果)也變的簡單了。

但是我們的項目目前還在8.0,需要考慮一下是否升級到9.0

6.2 方案二:storyboard拆分成xib

Storyboard的好處是,可以一眼看出app的邏輯架構,對於理解整個項目各個頁面之間的跳轉是有好處的,但是壞處顯而易見,他無法管理一個龐大的項目,因此很多工程采用的方案是xib,一個ViewController,對應一個xib,摒棄了storyboard,這樣擴展起來特別方便

但是問題是:原工程storyboard中,可能有三十多個ViewController,如何遷移過去是個麻煩的事

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved