轉載:Ryan's Zone
好的架構不是設計出來的愁拭,而是進化而來的庭砍!
寫在前面
從2011年底開始學習iOS開發(fā)噪叙,到現(xiàn)在也已經(jīng)快3年了改基,雖然中途沒有一直進行iOS的開發(fā)(總是在Android和iOS間切換),但始終沒有離開怕敬,而我現(xiàn)在的工作也一樣揣炕,在iOS和Android間來回游走,正如我博客的slogan一樣东跪,“In Android&iOS”畸陡。其實對我來說,兩個平臺沒有絕對的好壞越庇,我都喜歡檩淋、我都熱愛斟薇。有人會說央渣,同樣的產(chǎn)品在不同平臺做兩次不會覺得厭煩嗎低飒?這個問題我會給出肯定的回答,不會桑驱!因為如果你真的喜歡你所做的產(chǎn)品竭恬,做多少次都不會覺得煩,每一次的復盤都是一次改進的過程熬的,很多創(chuàng)新都是在重復的工作中產(chǎn)生的痊硕。在技術層面,同一套思想用不同的技術來實現(xiàn)押框,本身就是一個加強對不同平臺技術鞏固和理解的過程岔绸,技術本來就是來承載和表現(xiàn)業(yè)務的,在實現(xiàn)業(yè)務的過程中加強對業(yè)務的理解橡伞、實現(xiàn)對業(yè)務的創(chuàng)新盒揉,這或許也就是堆代碼和寫程序的區(qū)別吧!^_^
我的iOS工程結構
接下來兑徘,我就簡單介紹下我做iOS項目時使用的工程結構刚盈。首先要說的是,這只是我的工程結構挂脑,并不是規(guī)范藕漱,或許它存在很多問題和不規(guī)范的地方欲侮,我只是把它分享出來,給大家提供一個參考肋联,也希望收到大家的一些反饋來幫助我改進威蕉!
項目結構
下圖是我做iOS項目的一個常用工程結構,整體模式還是按照MVC的結構橄仍,只是在每一層做了一些細分處理忘伞,下面就簡單介紹下。
iOS工程中沒有像Java那樣非常嚴格的分包機制沙兰,不過在iOS工程中我們也可以通過Group的方式在工程中實現(xiàn)邏輯分包,這樣更有利于我們組織和管理代碼翘魄,使工程結構更清晰和易于理解鼎天。在我的工程結構中,主要有如下group:
Application:這個group中放的是AppDelegate和一些系統(tǒng)常量及系統(tǒng)配置文件暑竟;
Base:一些基本父類斋射,包括父ViewController和一些公用頂層自定義父類,其他模塊的類一般都繼承自這里的一些類但荤;
Controller:系統(tǒng)控制層罗岖,放置ViewController,均繼承于Group Base中的BaseViewController或BaseTableViewController腹躁;
View:系統(tǒng)中視圖層桑包,由于我比較喜歡通過代碼實現(xiàn)界面,所以這里放的都是繼承于UIView的視圖纺非,我將視圖從ViewController中分離出來全部放在這里哑了,這樣能保持ViewController的精簡;
Model:系統(tǒng)中的實體烧颖,通過類來描述系統(tǒng)中的一些角色和業(yè)務弱左,同時包含對應這些角色和業(yè)務的處理邏輯;
Handler:系統(tǒng)業(yè)務邏輯層炕淮,負責處理系統(tǒng)復雜業(yè)務邏輯拆火,上層調用者是ViewController;
Storage:簡單數(shù)據(jù)存儲涂圆,主要是一些鍵值對存儲及系統(tǒng)外部文件的存取们镜,包括對NSUserDefault和plist存取的封裝;
Network:網(wǎng)絡處理層(RTHttpClient)乘综,封裝了基于AFNetworking的網(wǎng)絡處理層憎账,通過block實現(xiàn)處理結果的回調,上層調用者是Handler層卡辰;
Database:數(shù)據(jù)層胞皱,封裝基于FMDB的sqlite數(shù)據(jù)庫存取和管理(RTDatabaseHelper)邪意,對外提供基于Model層對象的調用接口,封裝對數(shù)據(jù)的存儲過程反砌。
Utils:系統(tǒng)工具類(AppUtils)雾鬼,主要放置一些系統(tǒng)常用工具類;
Categories:類別宴树,對現(xiàn)有系統(tǒng)類和自定義類的擴展策菜;
Resource:資源庫,包括圖片酒贬,plist文件等又憨;
以上是對我的工程結構中各個group的介紹,通過以下登錄模塊的系統(tǒng)類圖锭吨,可以比較直觀的看到這種工程結構的全貌蠢莺。
整體來看分為三大塊,黃色區(qū)域的模型和業(yè)務邏輯層(M)零如,藍色區(qū)域的視圖層(V)躏将,紅色區(qū)域的視圖控制器層(C),其中考蕾,黃色區(qū)域實現(xiàn)了對業(yè)務邏輯和數(shù)據(jù)處理的封裝祸憋,對應他們的上層ViewController,可以實現(xiàn)非常簡單的接口調用肖卧,將業(yè)務復雜性從ViewController中抽離出來蚯窥,通過模塊化的方式,保證ViewController的可讀性和可維護性喜命。
保持ViewController簡單
往往大家都會抱怨iOS中ViewController寫著寫著就會越來越臃腫沟沙,那時因為隨著業(yè)務的復雜,功能的增多壁榕,所有的邏輯都包含在ViewController中矛紫,還包括一些諸如UITableViewDatasource的代理方法,使得ViewController臃腫不堪牌里,可維護性極低颊咬,耦合性也很高,為了使ViewController能更簡單牡辽,便于維護和后續(xù)的開發(fā)喳篇,給ViewController瘦身就顯得尤為必要,我的做法主要有三個方面态辛。
1麸澜、View視圖與ViewController分離
如果你用Storyboard或者xib這是當然的,我比較喜歡手寫代碼奏黑,所以不在ViewController里面嵌入過多的View層代碼是保證ViewController簡單的方法之一炊邦,那么编矾,可以將View部分的代碼單獨封裝到一個繼承自UIView的子類當中,然后通過自定義Delegate實現(xiàn)View與ViewController的通信馁害。
2窄俏、業(yè)務邏輯與ViewController分離
將網(wǎng)絡請求處理和復雜的業(yè)務邏輯以及數(shù)據(jù)的存取工作單獨放到Handler層,對ViewController只暴露簡單的調用接口和通過block或delegate實現(xiàn)的回調碘菜,這樣不僅能使我們的工程模塊化凹蜈,也能大大降低ViewController的復雜性,就不會出現(xiàn)既包括網(wǎng)絡處理又包括數(shù)據(jù)處理的冗長的ViewController代碼了忍啸。Handler通過block或delegate將處理完的結果回調給ViewController仰坦,ViewController再將結果與View視圖層相關聯(lián)處理,這樣就真正起到了MVC的作用计雌,整體原則就是缎岗,讓ViewController只關系和負責處理與它相關的事。
在BaseHandler.h中可以定義一些簡單的業(yè)務處理規(guī)則:
#import
/**
*??Handler處理完成后調用的Block
*/
typedefvoid(^CompleteBlock)();
/**
*??Handler處理成功時調用的Block
*/
typedefvoid(^SuccessBlock)(id?obj);
/**
*??Handler處理失敗時調用的Block
*/
typedefvoid(^FailedBlock)(id?obj);
@interfaceBaseHandler?:?NSObject
/**
*??獲取請求URL
*
*??@param?path
*??@return?拼裝好的URL
*/
+?(NSString?*)requestUrlWithPath:(NSString?*)path;
@end
在LoginHandler中就可以定義對LoginViewController暴露的調用接口白粉,在LoginHandler中封裝負責的網(wǎng)絡處理和業(yè)務處理邏輯,對LoginViewcontroller來說鼠渺,只需要調用這個方法并傳入對應的UserEntity實體對象和處理成功和失敗狀態(tài)下的回調block就可以了鸭巴。
#import?"BaseHandler.h"
#import?"UserEntity.h"
@interfaceLoginHandler?:?BaseHandler
/**
*??用戶登錄業(yè)務邏輯處理
*
*??@param?user
*??@param?success
*??@param?failed
*/
-?(void)executeLoginTaskWithUser:(UserEntity?*)user?success:(SuccessBlock)success?failed:(FailedBlock)failed;
@end
3、Datasource或Delegate與ViewController分離
在iOS開發(fā)中經(jīng)常用到的UITableView包含了一系列的代理方法拦盹,這些方法往往也是使得ViewController變長變復雜的元兇之一鹃祖,那么,將這些Datasource或Delegate分離出來也是行之有效的方法之一普舆,例如恬口,通過自定義Datasource類(實現(xiàn)UITableViewDatasource協(xié)議)來將跟UITableView相關的數(shù)據(jù)源處理代理方法都集中到一個特定的類當中,ViewController只需要設置這個自定義數(shù)據(jù)源類給UITableView沼侣,然后其他的就都可以交給自定義數(shù)據(jù)源類去處理了祖能。
我參考了Lighter View Controllers上的介紹改進了一個BaseTableViewProtocol,基本上常用的一些場景是可以使用的蛾洛,不過這個還得不斷優(yōu)化以適應更多的場景养铸,具體的代碼我放在Github上了,感興趣的同學可以去看看轧膘,使用方法可以參考上面鏈接中的介紹钞螟,基本類似,我的改進主要是支持對多section的適用谎碍。
寫在最后
以上是我在開發(fā)iOS項目中的一些總結和工程實踐鳞滨,其中肯定還是存在很多問題的,我也在不斷尋求改進的方法蟆淀,也歡迎各路高手給我提出意見和建議拯啦。關于這個工程結構的一個簡單事例我放在我的Github上了澡匪,感興趣的同學可以去看看RTLibrary-ios。