歡迎加入【iOS/Swift/OC開發(fā)交流群|127183325】交流學習? ? ?
? ? ? 公司項目的1.0版本已經(jīng)結(jié)束有一段時間了飞傀,2.0版本也逐漸進入尾聲皇型,從1.0版本結(jié)束就計劃著寫一下項目總結(jié),一是對項目進行一下思路梳理砸烦,二是總結(jié)一下之前的工作弃鸦,找到所遇到的問題和架構(gòu)的不合理之處,為接下來的版本做準備幢痘。由于2.0版本的任務比較緊急唬格,一直沒有時間做個系統(tǒng)的整理,只是零零星星的做了一些備注颜说、筆記什么的购岗。因為個人原因,準備回濟南發(fā)展门粪,所以向公司提出了辭職喊积。利用這段準備移交工作的時間做了一下項目版本1.0的總結(jié),希望能為新來的iOS同事快速進入狀態(tài)提供一些幫助玄妈。
由于項目還沒有上線乾吻,所以許多東西都?需要保密,?可能會有部分比較敏感的部分不會詳說措近。另外溶弟,由于項目后臺是公司內(nèi)網(wǎng),本文主要講講架構(gòu)的設計思路瞭郑,具體的技術(shù)細節(jié)和代碼就不往上貼了辜御,有時間可以另開一帖詳談。
1.0版本的項目總結(jié)分成以下部分:
一屈张、從架構(gòu)談起--架構(gòu)的分層和功能邏輯的細分擒权。
二袱巨、關(guān)于可復用性和可擴展性。
三碳抄、Block和Delegate的抉擇愉老。
四、關(guān)于第三方庫
五剖效、框架的進化--框架的持續(xù)優(yōu)化
一嫉入、從架構(gòu)談起--架構(gòu)的分層和功能邏輯的細分。
對于第一款從零開始主導開發(fā)的項目璧尸,在開始之前做足了功課咒林。雖然還是有缺陷,但是架構(gòu)不就是在不斷的試錯改錯中逐漸完善的嘛(給自己找了一個好借口爷光。垫竞。。)蛀序。
先說一下架構(gòu)的?原則欢瞪,參考之前看到的一篇文章,文章里面比較詳細的討論了在架構(gòu)設計中的一些關(guān)鍵原則徐裸。對此做的總結(jié)如下:
1.?需要分層遣鼓,將復雜的系統(tǒng)分解成比較容易實現(xiàn)的較小系統(tǒng)。
2.層內(nèi)部高內(nèi)聚倦逐,層與層之間低耦合譬正,層與層之間的訪問是透明的,不需要了解實現(xiàn)過程檬姥。
3.職責單一原則曾我,職責分工需要明確,邏輯盡量細分健民,依賴關(guān)系盡量少抒巢。
4.敏捷開發(fā)中需要思維收斂,不要做過多的發(fā)散秉犹,只設計必須的內(nèi)容蛉谜。
5.功能模塊化,模塊與模塊之間也不需要了解實現(xiàn)細節(jié)崇堵。
6.優(yōu)先考慮項目的擴展性和可伸縮性型诚,性能在初期不必過多考慮。
分層可以將復雜的系統(tǒng)細分成多個較為簡單的系統(tǒng)鸳劳,每一層只負責實現(xiàn)本層的功能狰贯,而不用去關(guān)心其它層的實現(xiàn)細節(jié),開發(fā)人員只關(guān)注本層的實現(xiàn)即可,功能實現(xiàn)上變得簡單涵紊,也提高了系統(tǒng)的伸縮性和擴展性傍妒。職責單一原則要求的功能細分的粒度盡量的小,功能實現(xiàn)不重復摸柄,不越權(quán)颤练,對于相對底層的模塊,可以更好的進行復用驱负。對于敏捷開發(fā)嗦玖,前期由于需求的不明確和不穩(wěn)定,我們可能注重的是功能的實現(xiàn)而不是大量的預先設計跃脊,所以我們盡量只設計必須的內(nèi)容踏揣,避免陷入多度設計的坑。對于最后一點不同的開發(fā)人員可能有不同的想法,個人認為在開發(fā)的初期優(yōu)先考慮擴展性和伸縮性可以更快的進行版本迭代,不斷地試錯岂贩,更快的做出一款用戶喜歡的產(chǎn)品妈踊,而性能瓶頸在初期并不明顯,只有在用戶達到一定數(shù)量的時候才會出現(xiàn)性能問題彰亥,而我們可以在逐步完善產(chǎn)品的過程中可以不斷地優(yōu)化咧七,逐步的提高軟件的性能。
先看一下此次項目的分層架構(gòu)設計圖:
從上圖可以看出任斋,各層之間數(shù)據(jù)的流動嚴格遵守著規(guī)則继阻,就是必須要通過業(yè)務邏輯層來進行交流。而各層的功能都是基于底層的功能之上废酷,層與層之間的交流通過設計好的具有一定規(guī)則的接口來進行瘟檩,不用關(guān)心具體的實現(xiàn),因此在業(yè)務邏輯發(fā)生變化的時候就可以將修改的范圍降到最少澈蟆。層與層之間只能與鄰近的層進行交互墨辛,不能跨層調(diào)用。每一層內(nèi)部又進行功能模塊的細分趴俘,模塊與模塊之間的交互也必須有一定的規(guī)則睹簇,模塊內(nèi)部高內(nèi)聚,模塊之間低耦合寥闪,模塊與模塊之間關(guān)注接口太惠,模塊內(nèi)部關(guān)注實現(xiàn),模塊內(nèi)部的修改不會影響其他的模塊疲憋。
分好層之后就可以著手進行具體的開發(fā)了凿渊。一般是從底層開始,最后實現(xiàn)View層。本項目中每層的實現(xiàn)的功能:
1嗽元、DataPresentation(數(shù)據(jù)持久層):數(shù)據(jù)的來源敛纲。數(shù)據(jù)來源有數(shù)據(jù)庫、服務器和內(nèi)存緩存剂癌,根據(jù)數(shù)據(jù)來源設計DAO淤翔、NET和DataCache三個模塊,三個模塊分別有自己的實現(xiàn)數(shù)據(jù)訪問的接口佩谷,然后通過統(tǒng)一的DataPresentation層向上部提供數(shù)據(jù)訪問的接口旁壮。上層不需要了解數(shù)據(jù)是怎么獲取到的。
2谐檀、BusinessLogic(業(yè)務邏輯層):核心業(yè)務邏輯抡谐,一般需要很高的復用性。業(yè)務邏輯層用來處理從View層傳過來的數(shù)據(jù)桐猬,處理完成后或者從底層數(shù)據(jù)層獲取相關(guān)數(shù)據(jù)然后更新到View層麦撵,或者直接更新View層,或者將相關(guān)數(shù)據(jù)存儲到網(wǎng)絡服務器或本地持久化或者緩存到內(nèi)存中溃肪。
3免胃、View(視圖層/表示層):數(shù)據(jù)的展示,處理繪圖惫撰、點擊或者手勢等事件羔沙。
下圖體現(xiàn)了在此項目中實現(xiàn)數(shù)據(jù)持久層各模塊之間的邏輯關(guān)系:
數(shù)據(jù)持久化的可選方案主要有屬性列表、對象歸檔厨钻、SQLite數(shù)據(jù)庫和Core Data(實質(zhì)上也是SQLite)扼雏。此次的項目選擇使用SQLite數(shù)據(jù)庫,使用FMDB這個十分優(yōu)秀的第三方庫夯膀。順便說一下诗充,在敏捷開發(fā)中,非常重要的一點是產(chǎn)品的快速迭代棍郎,然后不斷地試錯其障,不斷地進化,速度是很重要的涂佃,所以可以選擇一些比較成熟的框架來用励翼,這比自己重新實現(xiàn)來的要快。在使用第三方庫的時候有一點需要切記辜荠,由于第三方庫是由其他的開發(fā)者開發(fā)的汽抚,第三方庫提供的一些接口有可能在將來會發(fā)生改變,所以我們不能將第三方庫的接口散落到項目的各處伯病,我們需要在它們的上面封裝一層自己的接口造烁,以備將來第三方庫的接口改變或者替換其他的第三方庫否过。
網(wǎng)絡模塊的設計需要根據(jù)項目的具體需求來選擇HTTP協(xié)議或者TCP/IP協(xié)議。本項目因為需要遠程遙控和WAN/LAN文件傳輸惭蟋,另外還需要和web服務器進行通訊苗桂,所以項目中用到的協(xié)議有HTTP、TCP告组。另外煤伟,發(fā)現(xiàn)局域網(wǎng)內(nèi)的硬件設備使用了UDP協(xié)議。相關(guān)的協(xié)議就不在這詳說了木缝,只說一下用在了什么地方便锨。
1.HTTP,主要用在了和服務器的交互我碟,由于一開始看的MJ大神的教程放案,所以在設計這一模塊的時候深受其影響。因為感覺Block是如此的好用矫俺,所以就在此處大量的使用了類方法和Block吱殉,導致1.0版本在擴展性上大打折扣,后期更改需求的時候明顯感覺到困難厘托。也因為如此考婴,在進行2.0版本設計的時候基本上是對這一模塊進行了完全的重構(gòu),明確了哪些地方用Block催烘,哪些地方用Delegate。所以缎罢,雖然Block和Delegate在功能和所要解決的問題比較相似伊群,特別是Block在可讀性方面可能比Delegate更有優(yōu)勢,但Block并不能完全替代Delegate策精。更詳細的用法可以參看這篇文章舰始。
2.Socket,這一部分用在了兩個地方咽袜,一是遠程遙控丸卷,對控制命令的實時性要求比較高,需要使用TCP询刹;二是在局域網(wǎng)內(nèi)的文件傳輸谜嫉,也是用的TCP;三是用于發(fā)現(xiàn)局域網(wǎng)內(nèi)的硬件設備凹联,根據(jù)定義好的協(xié)議沐兰,手機端需要在局域網(wǎng)內(nèi)廣播UDP包,硬件端收到UDP包后也在局域網(wǎng)內(nèi)廣播自己的UDP包蔽挠,手機端對收到的包進行過濾后就可以發(fā)現(xiàn)所有在線的設備了住闯。想快速實現(xiàn)這一模塊的話可以使用CocoaAsyncSocket。
內(nèi)存緩存在1.0版本中設計的比較簡單,使用了單例設計模式比原,看下圖:
有內(nèi)存緩存機制的時候插佛,必須要考慮內(nèi)存警告和緩存數(shù)據(jù)過期的情況。
因為在數(shù)據(jù)持久層有三種途徑可以獲取數(shù)據(jù)量窘,所以就得設計一種存取數(shù)據(jù)的機制雇寇,或者說規(guī)則,比較通用的機制如下:
這張圖只是展示了獲取數(shù)據(jù)的一個過程绑改,在從服務器獲取數(shù)據(jù)后需要將數(shù)據(jù)在本地緩存谢床,緩存兩種途徑,一個是本地持久化厘线,即存入SQLite數(shù)據(jù)庫识腿,一個是內(nèi)存緩存。
好了造壮,數(shù)據(jù)持久層的設計就到此為止了渡讼。當然,這樣的設計肯定會有缺陷存在耳璧,但是不怕成箫,我們可以在以后的版本迭代升級中逐步的進行完善,我相信旨枯,只要我們不斷的找出在設計上的問題然后改正蹬昌,最終我們會構(gòu)建出一個優(yōu)秀的框架。