iOS電商類APP的研發(fā)

前言

本文是研發(fā)一個在線超市的電商類APP過程中苍糠,對架構(gòu)的整理叁丧。


功能:

  • 1、瀏覽商品、購買商品拥娄、切換商店坷衍;
  • 2、查看訂單条舔、訂單投訴枫耳、意見反饋;
  • 3孟抗、登陸迁杨、退出、收貨地址管理凄硼;
  • 4铅协、支付、取消訂單摊沉;
  • ...

箭頭的指關(guān)系 代表著 直接調(diào)用狐史,也代表著持有引用的意思。

所有的實例都可以通過監(jiān)聽event说墨,達到交流的效果骏全。

其中Model是單例,Controller 是storyBoard 上實例尼斧,view是Controller運行時加載并初始化姜贡;

Message是工廠模式,每一個協(xié)議都實例化一個對象來解決棺棵;

Event通過封裝NSNotifycation實現(xiàn)楼咳。

網(wǎng)絡通訊是通過Message調(diào)用AFNetworking。

設計中遇到的問題

1烛恤,網(wǎng)絡層請求的封裝

一開始的做法是定義一個server類來處理請求母怜,頭文件中定義請求的類型,所有的網(wǎng)絡請求都走server類缚柏,server類直接調(diào)用AFNetworking.
大致的形式如下:

Server:NSObject
{
    -(void) requestLogin;
    -(void) requestLogout;
  ....
}

這樣的好處是直接調(diào)用苹熏,開發(fā)方便,邏輯也比較簡單船惨。
壞處是柜裸,所有的代碼都寫在一起,不方便維護粱锐,同時不好做統(tǒng)一的邏輯處理(比如說session過期等)疙挺。

現(xiàn)在采用的做法:
定義一個BaseMessage,封裝AFNetworking的調(diào)用怜浅,還有統(tǒng)一的邏輯處理铐然。
同時定義OrderMessage,CartMessage,GoodsMessage,ShopMessage等繼承BaseMessage蔬崩,來具體實現(xiàn)特定的邏輯。
這樣做的好處搀暑,把邏輯分類沥阳,代碼按照模塊分散到每個SubMessage,方便維護自点。

還可以優(yōu)化的地方:
現(xiàn)在的請求是一個Message就是一個網(wǎng)絡請求(http)桐罕,處理完之后要在Message拋出事件,來通知其他模塊的信息桂敛。并且功炮,每個Message都是相互獨立的,并沒有統(tǒng)一調(diào)度的過程术唬。
可以新建一個MessageQueue類薪伏,來存放所有的Message請求,通過MessageQueue來調(diào)度http請求粗仓。
這樣的涉及到的問題是:結(jié)果回來后嫁怀,如何通知其他對象?
做法1:
當請求Message的時候借浊,self實現(xiàn)一個接口塘淑,并且傳入self;回調(diào)的時候巴碗,直接通過接口調(diào)用朴爬;
做法2:
請求的時候,帶一個閉包參數(shù)橡淆,回調(diào)的時候直接調(diào)用閉包;
做法3:
請求之后監(jiān)聽事件母赵;回調(diào)時通過事件響應逸爵;

比較理想的做法:
有controller 、 message 凹嘲、msgCenter三個實例师倔。
controller監(jiān)聽事件,發(fā)送message周蹭;
message實現(xiàn)接口趋艘,自己把自己添加進msgCenter隊列;
msgcenter對BaseMessage進行處理凶朗,通過接口來查詢message 里ID等詳細信息瓷胧;回調(diào)后,通過調(diào)用message的接口棚愤。
controller 和 message 用的是監(jiān)聽者模式搓萧;
msgCenter 和 message 之間用的是代理模式杂数;
msgCenter 可以實現(xiàn)異步的與服務器交互,和對message 的統(tǒng)一處理瘸洛。

2揍移,MVC框架的實現(xiàn)

iOS的設計,本身就含有很多MVC的思想反肋,比如說要實現(xiàn)一個自定義UITableView那伐,就要繼承UITableView,自定義delegate石蔗,與Controller的交流 是通過delegate實現(xiàn)罕邀。同時,一個頁面就是一個controller抓督,也要繼承UIViewController燃少。
自然而然地,在寫代碼的時候就會M(model)铃在、V(View)阵具、C(controller)的區(qū)分。
但在實際的需求中定铜,遇到一些正常的需求的時候阳液,如果沒有設計好,也會很棘手揣炕。
比如說:首頁下方的購物車模塊帘皿、商品展示的模塊,這些都是需要重復出現(xiàn)的模塊畸陡,也就是需要重用的模塊鹰溜。如何設計購物車模塊,使得購物車模塊 和 持有購物車的模塊(首頁丁恭、子類目等)之間沒有耦合曹动,也是一個麻煩的事情。
具體的需求有幾個:
1牲览、購物車點開的時候墓陈,頁面除購物車的背景要灰掉,同時購車要有上滑的動畫第献;
2贡必、點擊購物車或者點擊背景的時候,購物車彈下庸毫,同時灰色背景去除仔拟;
3、購物車中點擊商品的增減岔绸,要實時反饋到頁面上(首頁理逊、子類目等)橡伞;
4、購物車點開之后的大小晋被,由購物車內(nèi)的物品決定兑徘,有最大高度;
5羡洛、購物車的物品減到0的時候挂脑,不消除;
....

controller與view之間的交互欲侮,controller持有view崭闲,可以 直接調(diào)用view;view要調(diào)用controller或者其他view威蕉,可以通過事件刁俭、委托等方式;
不管是事件還是委托韧涨,為的是解耦牍戚,讓view與controller之間不耦合,所以切記不可在view定義一個controller的屬性虑粥,然后傳遞controller進來如孝。
解決方案:
view 與 controller 之間用委托(記得@property(weak),否則循環(huán)引用娩贷,內(nèi)存無法釋放)第晰;
view 與 view 之間用事件機制;

在interface builder可以用outlet 來做委托機制彬祖,非常方便茁瘦,具體的流程和UITableView類似;

3储笑,事件機制

沒有用第三方的事件機制腹躁,用的是NSNotifycation來實現(xiàn);
一開始的做法是:

#define NOTIFY_SERVER_USER_LOGIN     @"NOTIFY_SERVER_USER_LOGIN"
#define NOTIFY_UI_REQUEST_PHONE_CALL  @"NOTIFY_UI_REQUEST_PHONE_CALL"

直接define具體的協(xié)議南蓬,如果帶有數(shù)據(jù),就存到notify的userInfo哑了;
這樣在代碼寫了比較多時候赘方,當改動一個notify的userInfo的時候,經(jīng)常會忘記改其他的某處弱左,而且往往記不得userInfo里面的數(shù)據(jù)格式窄陡,不便于維護;

于是在NSNotify的基礎(chǔ)上做了一層封裝:
定義一個BaseEvent拆火,負責把event的類型轉(zhuǎn)成nsnotify(類型名字@""跳夭,屬性轉(zhuǎn)成dict)涂圆,同時把nsnotify轉(zhuǎn)成event;
同時Event分成幾類ErrorEvent ServerEvent UIEvent DataEvent等。
比如:

@interface UIMessageConfirmEvent : BaseEvent
 @property (nonatomic , copy) NSString* message;
@end

發(fā)送事件的時候币叹,可以直接在event類型里面給message賦值润歉;

開發(fā)中的原則

  • 1,不要有很大的文件颈抚,除非很少改動踩衩;(大文件,不方便維護和開發(fā))
  • 2贩汉,一個函數(shù)盡量只做一個功能驱富,如果有多個地方調(diào)用,要保證調(diào)用的意義是相同的匹舞;(盡量不要在調(diào)用參數(shù)中帶默認參數(shù)褐鸥,或者在復雜調(diào)用中帶flag來標示這次調(diào)用的含義)
  • 3,調(diào)用時的參數(shù)檢查赐稽,一般由被調(diào)用的函數(shù)檢查參數(shù)叫榕;如果涉及到參數(shù)不對時,需要有相應的邏輯操作又憨,比如彈出提示框等的翠霍,盡量由調(diào)用者來檢查參數(shù);

開發(fā)中的問題

問題1:model要不要監(jiān)聽事件蠢莺?

目前寒匙,Model需要被改變的時候是:
1、viewController請求數(shù)據(jù)時候躏将;
2锄弱、message發(fā)生變化的時候掌动;(比如說登陸邻遏、注銷泵殴、商店切換)

壞處:message處有各個model的代碼切厘。
比如說切換商店后外邓,就有這些變換止吁;

       [self lyPostNotification:NOTIFY_INDEX_DATA];
       [[CartModel instance] onShopChange];        [[CategoryDetailModel instance] onShopChange];
       [[ServiceModel instance] onShopChange];

登出后把篓,需要把這些Model清空单旁;

   [self lyPostNotification:NOTIFY_USER_LOGOUT];
   [[CartModel instance] clearCache];    [[AddressModel instance] clearCache];    [[UserModel instance] clearCache];
   [[OrderModel instance] clearCache];

如果新增model比如說新添加的serviceModel拦赠,需要在message處添加相應的邏輯代碼巍沙;

還有的問題是,Model的clearCache等函數(shù)被message調(diào)用荷鼠,耦合性特別強句携;相當于做了事情A(登出),接著馬上做事情B(清空數(shù)據(jù))允乐,而且是直接調(diào)用矮嫉,以后修改起來很容易犯錯誤削咆。

設想:
如果model監(jiān)聽事件的話;
那么model只需監(jiān)聽各個事件蠢笋,然后再寫處理函數(shù)拨齐;
model的邏輯都聚合在自身;

帶來的后果是挺尿,model稍微變大奏黑。多個事件,和多個處理函數(shù)编矾。
不過這個如果是message處來調(diào)用熟史,處理函數(shù)還是一樣要寫,只是多了事件處理監(jiān)聽的代碼窄俏。
model的邏輯是聚合了蹂匹,但是注銷的邏輯分散了,看不出來注銷完干了什么事情凹蜈。這個問題好像也不是問題限寞,因為可以查看事件的監(jiān)聽者,看到監(jiān)聽了注銷事件的model仰坦。
有一處代碼履植,集合了所有的model instance。所有的model都必須先初始化悄晃。否則無法監(jiān)聽事件玫霎。

問題2:調(diào)用message的時候,message從各個model獲取了數(shù)據(jù)妈橄,那么庶近,誰來做參數(shù)檢查?

1眷蚓,誰調(diào)用(不同層次之間)鼻种,誰負責檢查參數(shù);比如orderMessage需要用戶登錄沙热,那么調(diào)用orderMessage的時候叉钥,就必須保證已經(jīng)登錄。(因為message和model不在同一層次)
2篙贸,如果是檢查的內(nèi)容是自身內(nèi)容沼侣,那么由自己負責。

問題3:從頁面A (ControllerA) 跳到 頁面B(ControllerB)歉秫,用戶的操作數(shù)據(jù)(比如說留言),怎么合適地從A傳到B养铸?


這個是1.5版本架構(gòu)具體的實現(xiàn)雁芙,參考兩個概念MVP MVVM轧膘。
讓顯示邏輯和業(yè)務邏輯有所分開,是比較重要的兔甘。
待完成微信端的開發(fā)谎碍,再來寫一版詳細的改動日志。 (然而不可能)

附錄

蘑菇街的IM 網(wǎng)絡層:

API center 負責管理洞焙、注冊所有的API蟆淀;接受服務器數(shù)據(jù)(可以分離連接代買,僅提供接受數(shù)據(jù)的接口)澡匪,調(diào)用解析接口熔任,回調(diào)API;超時處理唁情;有自己的線程疑苔。
有一個SuperAPI 還有一個 APIProtocal
superAPI 是所有API的基類,負責注冊request和respone甸鸟、timeout惦费、保存返回閉包、打包數(shù)據(jù)(調(diào)用protocal)抢韭、發(fā)送數(shù)據(jù)薪贫。
APIProtocal封裝了協(xié)議的解析、打包刻恭。
controller調(diào)用實現(xiàn)了Protocal的superAPI子類(childAPI)瞧省,并且把回調(diào)函數(shù)的閉包傳遞進去,放在superAPI吠各。
childAPI實現(xiàn)了APIProtocal 從而對服務器返回的數(shù)據(jù)解析臀突,并且返回cmd、msgID贾漏。

APIcenter 有四個map(request response notify timeout)
request是請求 response是回復 timeout是超時處理 notify是服務器通知候学。
每一次通訊,都需要注冊request纵散、response梳码、timeout。
消息處理完后伍掀,remove from map掰茶。(notify不需要remove)

流程如下:

1.controller 調(diào)用 childAPI的request,傳入數(shù)據(jù)(object)蜜笤,和completion閉包濒蒋。
2.childAPI->superAPI 的request統(tǒng)一處理流程,在center,注冊request和respone沪伙、timeout瓮顽、保存返回閉包、打包數(shù)據(jù)(調(diào)用protocal)围橡、發(fā)送數(shù)據(jù)暖混。
3.superAPI通過APIProtocol 調(diào)用childAPI的數(shù)據(jù)打包,調(diào)用center 的發(fā)送翁授。
4.center收到tcp返回的bytes拣播,調(diào)用protocal(在responseMap注冊的API)解析。
5.解析完成清除map中的API(request收擦、response贮配、timeout),在主線程回調(diào)completion閉包炬守,并且將數(shù)據(jù)傳遞過去牧嫉。
6.controller 收到數(shù)據(jù),存到model减途,顯示處理酣藻。
7.如果在4過程中,timeout到了鳍置,那么直接清除request辽剧、resonse、timeout税产,回調(diào)timeout閉包怕轿。

總結(jié)

  • 1,一個函數(shù)盡量只做一個功能辟拷,如果有多個地方調(diào)用撞羽,要保證意義相同。(這樣才能復用衫冻,不要帶flag的參數(shù)诀紊,混亂)
  • 2,業(yè)務邏輯隅俘、顯示邏輯的代碼 集合在一起邻奠。(ReactiveCocoa)
  • 3,盡量少出現(xiàn)allModel为居、allEvent 的東西碌宴,不方便添加,多人開發(fā)會沖突蒙畴;
  • 4贰镣,發(fā)現(xiàn)改一個東西,需要改很多處代碼的時候,要考察下關(guān)系問題;

Callback block 代替delegate和event進行回調(diào)八孝,實現(xiàn)業(yè)務聚合董朝,(注意,這里不能代替某些event干跛,比如說登出、拉取訂單等祟绊,但是最好這些可以反映到model楼入,由model發(fā)出變化事件)最合適用于只有一次event 監(jiān)聽,的event牧抽。
ViewController的瘦身是MVC實現(xiàn)的要點嘉熊,用Category、業(yè)務細分然后把delegate把代碼劃分到對應的類扬舒。

后記

MVC阐肤、MVVM、MVP都是很不錯的思想讲坎,設計模式里面更是前人經(jīng)驗的總結(jié)孕惜。
原本計劃在做完整個APP再進行一次總結(jié),可后來做微信端的開發(fā)晨炕,學習Angular-js花費了一大塊的時間衫画。再后來,就喜歡玩其他東西了瓮栗。

培養(yǎng)一些興趣削罩,這些興趣不是物質(zhì)的享受,而是一種能讓你思考费奸,進步的興趣弥激。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市愿阐,隨后出現(xiàn)的幾起案子微服,更是在濱河造成了極大的恐慌,老刑警劉巖换况,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件职辨,死亡現(xiàn)場離奇詭異,居然都是意外死亡戈二,警方通過查閱死者的電腦和手機舒裤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來觉吭,“玉大人腾供,你說我怎么就攤上這事。” “怎么了伴鳖?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵节值,是天一觀的道長。 經(jīng)常有香客問我榜聂,道長搞疗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任须肆,我火速辦了婚禮匿乃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘豌汇。我一直安慰自己幢炸,他們只是感情好,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布拒贱。 她就那樣靜靜地躺著宛徊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逻澳。 梳的紋絲不亂的頭發(fā)上闸天,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音赡盘,去河邊找鬼号枕。 笑死,一個胖子當著我的面吹牛陨享,可吹牛的內(nèi)容都是我干的葱淳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抛姑,長吁一口氣:“原來是場噩夢啊……” “哼赞厕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起定硝,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤皿桑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蔬啡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诲侮,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年箱蟆,在試婚紗的時候發(fā)現(xiàn)自己被綠了沟绪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡空猜,死狀恐怖绽慈,靈堂內(nèi)的尸體忽然破棺而出恨旱,到底是詐尸還是另有隱情,我是刑警寧澤坝疼,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布搜贤,位于F島的核電站,受9級特大地震影響钝凶,放射性物質(zhì)發(fā)生泄漏仪芒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一耕陷、第九天 我趴在偏房一處隱蔽的房頂上張望桌硫。 院中可真熱鬧,春花似錦啃炸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至掏湾,卻和暖如春裹虫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背融击。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工筑公, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尊浪。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓匣屡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拇涤。 傳聞我的和親對象是個殘疾皇子捣作,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

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