基于 MVC 的項(xiàng)目重構(gòu)

前言

最近公司的項(xiàng)目要更新所有界面的 UI 風(fēng)格,趁此機(jī)會(huì)正好把項(xiàng)目重構(gòu)一遍,本文主要記錄重構(gòu)時(shí)的一些選擇和解決的問題。

背景

首先說說背景,也就是為什么要重構(gòu)熟吏,因?yàn)橹貥?gòu)是需要成本的,一不小心修改錯(cuò)了玄窝,就會(huì)讓原來完好的產(chǎn)品出各種問題牵寺,所以先總結(jié)下為什么,主要是以下四個(gè)問題:

  • 1.沒有統(tǒng)一的代碼風(fēng)格
    這個(gè)就比較痛苦了恩脂,因?yàn)闅v史的原因帽氓,或者說這個(gè)項(xiàng)目初期就沒有代碼規(guī)范,在接手項(xiàng)目前俩块,代碼風(fēng)格就非常隨意黎休、天馬行空。在此期間我重構(gòu)了一部分玉凯,但仍有一大半不規(guī)范的代碼势腮。
  • 2.臃腫的 ViewController
    這個(gè)好理解,一個(gè)類幾千行代碼漫仆,應(yīng)該的不應(yīng)該的都擠在一起捎拯。
  • 3.難以理解的邏輯代碼
    業(yè)務(wù)邏輯代碼混亂不堪,看的頭疼盲厌,還不敢亂刪署照。
  • 4.混亂的類調(diào)用
    沒有明確一個(gè)類該做什么,全都堆在一起吗浩。

追求代碼質(zhì)量是一個(gè)優(yōu)秀程序員對(duì)自己的要求建芙,所以趁這個(gè)機(jī)會(huì),決定把整個(gè)項(xiàng)目重構(gòu)一遍懂扼。

架構(gòu)的選擇

當(dāng)前在 iOS 開發(fā)上有很多熱門的架構(gòu)模式禁荸,如 MVC、MVVM阀湿、MVCS屡限、VIPER 等等。對(duì)此我的觀點(diǎn)是:架構(gòu)的選擇要結(jié)合具體的情況炕倘,比如業(yè)務(wù)的復(fù)雜度、開發(fā)人員的接受程度翰撑,以及重構(gòu)的時(shí)間周期等等罩旋,選擇一個(gè)對(duì)的架構(gòu)比選擇一個(gè)復(fù)雜的架構(gòu)更為重要啊央。
在老項(xiàng)目里選擇的是 MVC,對(duì)于項(xiàng)目中的絕大部分場(chǎng)景來說涨醋,MVC 沒有成為制約業(yè)務(wù)發(fā)展的瓶頸瓜饥,同時(shí)考慮到新項(xiàng)目的學(xué)習(xí)成本以及重構(gòu)時(shí)間周期的問題,所以在新項(xiàng)目上還是選擇了 MVC浴骂。

統(tǒng)一的代碼風(fēng)格

無規(guī)矩不成方圓乓土,在老項(xiàng)目里由于流程的缺失和開發(fā)人員的更迭,一直沒有一個(gè)統(tǒng)一的編碼規(guī)范溯警。而在多人開發(fā)時(shí)趣苏,保持統(tǒng)一的編碼規(guī)范是很有必要的,這樣易于保持代碼一致性和 Code Review梯轻。所以確定了架構(gòu)之后食磕,接著就是確定編碼規(guī)范。
下面是編碼規(guī)范里一些需要注意的點(diǎn):

命名

使用可讀的駝峰命名法去給類喳挑、方法彬伦、變量命名。
常量應(yīng)該使用駝峰式命名規(guī)則伊诵,所有的單詞首字母大寫和加上與類名有關(guān)的前綴单绑。

代碼分塊

在函數(shù)分組和protocol/delegate實(shí)現(xiàn)中使用#pragma mark -來分類方法,要遵循以下一般結(jié)構(gòu):

#pragma mark - Lifecycle

- (instancetype)init {}
- (void)dealloc {}
- (void)viewDidLoad {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}

#pragma mark - Custom Accessors

- (void)setCustomProperty:(id)value {}
- (id)customProperty {}

#pragma mark - IBActions

- (IBAction)submitData:(id)sender {}

#pragma mark - Public

- (void)publicMethod {}

#pragma mark - Private

- (void)privateMethod {}

#pragma mark - Protocol conformance

留空白

  • 建議使用tabs 而不是使用空格,tabs縮進(jìn)使用4個(gè)空格曹宴,確保在Xcode偏好設(shè)置來設(shè)置搂橙。
  • 文件結(jié)束時(shí)留一行空白
  • 用足夠的空行把代碼分割為合理的邏輯塊,而不是非常緊湊
  • 不要在一行代碼結(jié)尾處留空格
  • 更不要在空行(\n)中使用縮進(jìn)(\t)

代碼塊縮進(jìn)

(if/else/switch/while etc.)或者method function 的大括號(hào)留在當(dāng)前行浙炼,并前保留一個(gè)空格 份氧,能省略的不要添加

if user.isHappy {
  // Do something
} else {
  // Do something else
}

不推薦

if (user.isHappy )          多余空格
{                  換行位置不對(duì)
  // Do something
}
else {
  // Do something else
}

項(xiàng)目層級(jí)劃分

物理層級(jí)

上文確認(rèn)了項(xiàng)目架構(gòu)是以 MVC 為主,所以這里推薦使用 MVC + 按業(yè)務(wù)劃分項(xiàng)目層級(jí)的方式弯屈。具體的如下圖:


整個(gè)項(xiàng)目主要分為4個(gè)文件夾蜗帜,分別是:

  • AppDelegate: 程序入口。
  • Classes: 存放主要代碼文件资厉。
  • Resources: 存放資源文件厅缺,如圖片、音頻宴偿、視頻湘捎、 HTML 文件等。
  • Supporting Files: 存放配置文件窄刘,如 Info.plist窥妇、main.m、pch 文件等娩践。

而其中 Classes 目錄下活翩,又細(xì)分如下圖:


  • General:存放一些通用的類烹骨,如基類、Category材泄、Model 等沮焕。
  • Sections:按業(yè)務(wù)模塊細(xì)分 MVC。
  • Helpers:存放各種工具類拉宗。
  • Venders:存放需要手動(dòng)引入的第三方庫峦树。
  • Macro:存放全局頭文件,各種宏定義旦事,常量等魁巩。

代碼邏輯層級(jí)

從代碼邏輯上,大致分為 5 層

  • 網(wǎng)絡(luò)層:負(fù)責(zé)和服務(wù)器通訊獲取數(shù)據(jù)族檬。
  • 數(shù)據(jù)層:存儲(chǔ)用戶的數(shù)據(jù)歪赢,包括內(nèi)存cache。
  • 業(yè)務(wù)層:包含各種業(yè)務(wù)邏輯单料。
  • UI數(shù)據(jù)層:負(fù)責(zé)提供UI層所需要的數(shù)據(jù)埋凯,UI只和這層打交道。
  • UI層:包括ViewController和View扫尖,處理用戶的輸入白对。

分層使項(xiàng)目更清晰,開發(fā)時(shí)做到各個(gè)層獨(dú)立换怖,高內(nèi)聚甩恼、低耦合。

布局規(guī)范

AutoLayout

老項(xiàng)目是純 Frame 布局沉颂,代碼里有一大堆 Magic Number条摸,一大堆屏幕尺寸判斷,而這些造成了項(xiàng)目里有過多的布局代碼铸屉,對(duì)于剛上手項(xiàng)目的人來說也不太容易看懂钉蒲。所以這次重構(gòu)整體采用 AutoLayout 布局,摒棄老項(xiàng)目里的純 Frame 布局方式彻坛,精簡(jiǎn)代碼顷啼。

Xib/Storyboard

手寫 UI 和 Xib/Storyboard 誰優(yōu)誰劣這里不做討論,但有一點(diǎn)我認(rèn)為 Xib/Storyboard 是比手寫 UI 要快的昌屉。而這次重構(gòu)工作量大工期緊钙蒙,所以摒棄老項(xiàng)目里的手寫 UI ,改用 Xib/Storyboard 间驮。

精簡(jiǎn) ViewController

這一部分我認(rèn)為是本次重構(gòu)的重頭戲躬厌,也是本次重構(gòu)的主要目的所在,精簡(jiǎn) ViewController 里的代碼竞帽,解決老項(xiàng)目中 Massive ViewController 的問題烤咧。
主要工作分為以下幾步:

  • 1.保留最重要的任務(wù)偏陪,拆分其它不重要的任務(wù)。
  • 2.拆分后的模塊要盡可能提高可復(fù)用性煮嫌,盡量做到DRY
  • 3.提高拆分模塊后的抽象度

胖 Model 的問題

上文精簡(jiǎn) ViewController 把代碼都加入到 Model 里去,所以會(huì)造成胖 Model 的問題抱虐。對(duì)此我的理解是昌阿,除了優(yōu)化外,代碼的總量是確定的恳邀,一方的精簡(jiǎn)必然會(huì)造成一方的增加懦冰,而 Model 在這里是用來幫 ViewController 處理業(yè)務(wù)邏輯的,也就是說胖 Model 包含了部分弱業(yè)務(wù)邏輯谣沸。胖 Model 要達(dá)到的目的是刷钢,Controller從胖 Model 這里拿到數(shù)據(jù)之后,不用額外做操作或者只要做非常少的操作乳附,就能夠?qū)?shù)據(jù)直接應(yīng)用在 View 上内地,從這點(diǎn)上看胖 Model 也是可以接受的。

單元測(cè)試

老項(xiàng)目是不寫測(cè)試代碼的赋除,也沒有寫單元測(cè)試的條件阱缓。想想一個(gè)類堆砌幾千行代碼,想寫也不好下手举农,但既然重構(gòu)了荆针,單元測(cè)試也得補(bǔ)上。
單元測(cè)試對(duì)于目前來說颁糟,就是為了方便測(cè)試一些功能是否正常運(yùn)行航背,還有調(diào)試接口是否能正常使用。
有時(shí)候你可能是為了測(cè)試某一個(gè)網(wǎng)絡(luò)接口棱貌,然后每次都重新啟動(dòng)并且經(jīng)過很多操作之后才測(cè)試到了那個(gè)網(wǎng)絡(luò)接口玖媚,如果使用了單元測(cè)試,就可以直接測(cè)試那個(gè)方法键畴,相對(duì)方便很多最盅。
比如由于修改較多,想測(cè)試一下分享功能是否正常起惕,這時(shí)候就有用了涡贱。或者直接看一些接口返回的數(shù)據(jù)也會(huì)非常直觀惹想,不用啟動(dòng)整個(gè)工程问词。

TODO

在這也列舉兩個(gè)接下來可以做的事,先添加到 ToDoList 里嘀粱。

  • URLRoute

  • 模塊化

最后

其實(shí)總結(jié)起來就三點(diǎn)激挪,盡量保證:

  • Controller 里的代碼盡可能的少
  • Model 的功能盡可能的完整
  • View 盡可能獨(dú)立

就能構(gòu)建一個(gè)容易維護(hù)辰狡,便于協(xié)同的項(xiàng)目。

本文只是在項(xiàng)目重構(gòu)中總結(jié)的一些比較重要的點(diǎn)垄分,并不意味著都是最優(yōu)解宛篇。而我在項(xiàng)目的架構(gòu)和代碼的組織上經(jīng)驗(yàn)尚淺,若本文有什么錯(cuò)誤或是有更好的方法請(qǐng)直接指出薄湿,歡迎交流討論叫倍。

Reference

iOS應(yīng)用架構(gòu)談 view層的組織和調(diào)用方案

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市豺瘤,隨后出現(xiàn)的幾起案子吆倦,更是在濱河造成了極大的恐慌,老刑警劉巖坐求,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚕泽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡桥嗤,警方通過查閱死者的電腦和手機(jī)须妻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砸逊,“玉大人璧南,你說我怎么就攤上這事∈σ荩” “怎么了司倚?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)篓像。 經(jīng)常有香客問我动知,道長(zhǎng),這世上最難降的妖魔是什么员辩? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任盒粮,我火速辦了婚禮,結(jié)果婚禮上奠滑,老公的妹妹穿的比我還像新娘丹皱。我一直安慰自己,他們只是感情好宋税,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布摊崭。 她就那樣靜靜地躺著,像睡著了一般杰赛。 火紅的嫁衣襯著肌膚如雪呢簸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音根时,去河邊找鬼瘦赫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蛤迎,可吹牛的內(nèi)容都是我干的确虱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼忘苛,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蝉娜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起扎唾,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎南缓,沒想到半個(gè)月后胸遇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汉形,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年纸镊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片概疆。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逗威,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出岔冀,到底是詐尸還是另有隱情凯旭,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布使套,位于F島的核電站罐呼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏侦高。R本人自食惡果不足惜嫉柴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奉呛。 院中可真熱鬧计螺,春花似錦、人聲如沸瞧壮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馁痴。三九已至谊娇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背济欢。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工赠堵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人法褥。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓茫叭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親半等。 傳聞我的和親對(duì)象是個(gè)殘疾皇子揍愁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容