先上圖:

功能:
1、瀏覽商品,購買商品,支付;
2、切換商店、查看訂單、訂單投訴、意見反饋;
3、登陸、收貨地址管理;
4、app首次啟動的初始化界面;
架構上:

箭頭的指關系 代表着 直接調用,也代表着持有引用的意思。
所有的實例都可以通過監聽event,達到交流的效果。
其中Model是單例,Controller 是storyBoard 上實例,view是Controller運行時加載並初始化;
Message是工廠模式,每一個協議都實例化一個對象來解決;
Event通過封裝NSNotifycation實現。
網絡通訊是通過Message調用AFNetworking。
設計中遇到的問題:
1,網絡層請求的封裝。一開始的做法是定義一個server類來處理請求,頭文件中定義請求的類型,所有的網絡請求都走server類,server類直接調用AFNetworking.
大致的形式如下:
Server:NSObject
{
-(void) requestLogin;
-(void) requestLogout;
....
}
這樣的好處是直接調用,開發方便,邏輯也比較簡單。
壞處是,所有的代碼都寫在一起,不方便維護,同時不好做統一的邏輯處理(比如說session過期等)。
現在采用的做法:
定義一個BaseMessage,封裝AFNetworking的調用,還有統一的邏輯處理。
同時定義OrderMessage,CartMessage,GoodsMessage,ShopMessage等繼承BaseMessage,來具體實現特定的邏輯。
這樣做的好處,把邏輯分類,代碼按照模塊分散到每個SubMessage,方便維護。
還可以優化的地方:
現在的請求是一個Message就是一個網絡請求(http),處理完之后要在Message拋出事件,來通知其他模塊的信息。並且,每個Message都是相互獨立的,並沒有統一調度的過程。
可以新建一個MessageQueue類,來存放所有的Message請求,通過MessageQueue來調度http請求。
這樣的涉及到的問題是:結果回來后,如何通知其他對象?
做法1:
當請求Message的時候,self實現一個接口,並且傳入self;回調的時候,直接通過接口調用;
做法2:
請求的時候,帶一個閉包參數,回調的時候直接調用閉包;
做法3:
請求之后監聽事件;回調時通過事件響應;
比較理想的做法:
有controller 、 message 、msgCenter三個實例。
controller監聽事件,發送message;
message實現接口,自己把自己添加進msgCenter隊列;
msgcenter對BaseMessage進行處理,通過接口來查詢message 里ID等詳細信息;回調后,通過調用message的接口。
controller 和 message 用的是監聽者模式;
msgCenter 和 message 之間用的是代理模式;
msgCenter 可以實現異步的與服務器交互,和對message 的統一處理。
( http://www.cnblogs.com/loying/p/4804566.html 參考自 蘑菇街的IM 網絡層)
2,MVC框架的實現。ios的設計,本身就含有很多MVC的思想,比如說要實現一個自定義UITableView,就要繼承UITableView,自定義delegate,與Controller的交流 是通過delegate實現。同時,一個頁面就是一個controller,也要繼承UIViewController。
自然而然地,在寫代碼的時候就會M(model)、V(View)、C(controller)的區分。
但在實際的需求中,遇到一些正常的需求的時候,如果沒有設計好,也會很棘手。
比如說:首頁下方的購物車模塊、商品展示的模塊,這些都是需要重復出現的模塊,也就是需要重用的模塊。如何設計購物車模塊,使得購物車模塊 和 持有購物車的模塊(首頁、子類目等)之間沒有耦合,也是一個麻煩的事情。
具體的需求有幾個:
1、購物車點開的時候,頁面除購物車的背景要灰掉,同時購車要有上滑的動畫;
2、點擊購物車或者點擊背景的時候,購物車彈下,同時灰色背景去除;
3、購物車中點擊商品的增減,要實時反饋到頁面上(首頁、子類目等);
4、購物車點開之后的大小,由購物車內的物品決定,有最大高度;
5、購物車的物品減到0的時候,不消除;
....
controller與view之間的交互,controller持有view,可以 直接調用view;view要調用controller或者其他view,可以通過事件、委托等方式;
不管是事件還是委托,為的是解耦,讓view與controller之間不耦合,所以切記不可在view定義一個controller的屬性,然后傳遞controller進來。
解決方案:
view 與 controller 之間用委托(記得@property(weak),否則循環引用,內存無法釋放);
view 與 view 之間用事件機制;
在interface builder可以用outlet 來做委托機制,非常方便,具體的流程和UITableView類似;
3,事件機制
沒有用第三方的事件機制(如EventBus等),用的是NSNotifycation來實現;
一開始的做法是:
#define NOTIFY_SERVER_USER_LOGIN @"NOTIFY_SERVER_USER_LOGIN"
#define NOTIFY_UI_REQUEST_PHONE_CALL @"NOTIFY_UI_REQUEST_PHONE_CALL"
直接define具體的協議,如果帶有數據,就存到notify的userInfo;
這樣在代碼寫了比較多時候,當改動一個notify的userInfo的時候,經常會忘記改其他的某處,而且往往記不得userInfo里面的數據格式,不便於維護;
於是在NSNotify的基礎上做了一層封裝:
定義一個BaseEvent,負責把event的類型轉成nsnotify(類型名字@"",屬性轉成dict),同時把nsnotify轉成event;
同時Event分成幾類ErrorEvent ServerEvent UIEvent DataEvent等。
比如:
@interface UIMessageConfirmEvent : BaseEvent
@property (nonatomic , copy) NSString* message;
@end
發送事件的時候,可以直接在event類型里面給message賦值;
開發中的幾個原則:
1,不要有很大的文件,除非很少改動;(大文件,不方便維護和開發)
2,一個函數盡量只做一個功能,如果有多個地方調用,要保證調用的意義是相同的;(盡量不要在調用參數中帶默認參數,或者在復雜調用中帶flag來標示這次調用的含義)
3,調用時的參數檢查,一般由被調用的函數檢查參數;如果涉及到參數不對時,需要有相應的邏輯操作,比如彈出提示框等的,盡量由調用者來檢查參數;