今天寫(xiě)這篇博客是想達(dá)到拋磚引玉的作用,想與大家交流一下思想,相互學(xué)習(xí),博文中有不足之處還望大家批評(píng)指正,
iOS開(kāi)發(fā)之淺談MVVM的架構(gòu)設(shè)計(jì)與團(tuán)隊(duì)協(xié)作
。本篇博客的內(nèi)容沿襲以往博客的風(fēng)格,也是以干貨為主,偶爾扯扯咸蛋(哈哈~不好好工作又開(kāi)始發(fā)表博客啦~)。由于本人項(xiàng)目經(jīng)驗(yàn)有限,關(guān)于架構(gòu)設(shè)計(jì)方面的東西理解有限,我個(gè)人對(duì)MVVM的理解主要是借鑒于之前的用過(guò)的MVC的Web框架~在學(xué)校的時(shí)候用過(guò)ThinkPHP框架,和SSH框架,都是MVC的架構(gòu)模式,今天MVVM與傳統(tǒng)的MVC可謂是極為相似,也可以說(shuō)是兄弟關(guān)系,也就是一家人了。
說(shuō)道架構(gòu)設(shè)計(jì)和團(tuán)隊(duì)協(xié)作,這個(gè)對(duì)App的開(kāi)發(fā)還是比較重要的。即使作為一個(gè)專(zhuān)業(yè)的搬磚者,前提是你這磚搬完放在哪?不只是Code有框架,其他的東西都是有框架的,比如橋梁等等神馬的~在這兒就不往外扯了。一個(gè)好的工程框架不進(jìn)可以提高團(tuán)隊(duì)的協(xié)作效率,同時(shí)還可以減少代碼的冗余度和耦合性,合理的分工與系統(tǒng)的架構(gòu)設(shè)計(jì)是少不了的。
至于團(tuán)隊(duì)協(xié)作不僅僅是有SVN或者Git這些版本控制工具就行的,至于如何在iOS開(kāi)發(fā)中使用SVN,請(qǐng)參考之前的博客(iOS開(kāi)發(fā)之版本控制(SVN))。一個(gè)團(tuán)隊(duì)可以高效的工作,本人覺(jué)得交流是最為重要的,團(tuán)隊(duì)中的每個(gè)人都比較和氣,而且交流上沒(méi)有什么障礙(不過(guò)有的團(tuán)隊(duì)中總有幾個(gè)合不來(lái)的人),交流在團(tuán)隊(duì)中最為重要。至于SVN怎么用,那都不是事兒!
好了今天就以我寫(xiě)的一個(gè)Demo來(lái)淺談一下iOS開(kāi)發(fā)中的架構(gòu)設(shè)計(jì)和團(tuán)隊(duì)協(xié)作,今天的咸蛋先到這兒,切入今天的話題。
為了寫(xiě)今天的博客我花了點(diǎn)時(shí)間做了個(gè)工程,這個(gè)工程后臺(tái)的接口用的 的API來(lái)進(jìn)行測(cè)試的,在本文的后面也會(huì)跟上GitHub的分享鏈接。OK~說(shuō)的高大上一些就是,仁者見(jiàn)仁智者見(jiàn)智,交流思想,共同學(xué)習(xí)。
一、小酌一下MVVM
在這呢也不贅述什么是MVC,神馬又是MVVM了,在百度上谷歌一下一抓一大把,在這兒就簡(jiǎn)單的提上一嘴。下面的Demo用的就是MVVM的架構(gòu)模式。
Model層是少不了的了,我們得有東西充當(dāng)DTO(數(shù)據(jù)傳輸對(duì)象),當(dāng)然,用字典也是可以的,編程么,要靈活一些。Model層是比較薄的一層,如果學(xué)過(guò)Java的小伙伴的話,對(duì)JavaBean應(yīng)該不陌生吧。
ViewModel層,就是View和Model層的粘合劑,他是一個(gè)放置用戶輸入驗(yàn)證邏輯,視圖顯示邏輯,發(fā)起網(wǎng)絡(luò)請(qǐng)求和其他各種各樣的代碼的極好的地方。說(shuō)白了,就是把原來(lái)ViewController層的業(yè)務(wù)邏輯和頁(yè)面邏輯等剝離出來(lái)放到ViewModel層。
View層,就是ViewController層,他的任務(wù)就是從ViewModel層獲取數(shù)據(jù),然后顯示。
上面對(duì)MVVM就先簡(jiǎn)單的這么一說(shuō),好好的理解并應(yīng)用的話,還得實(shí)戰(zhàn)。
二、關(guān)于工程中是否使用StoryBoard的論述
從網(wǎng)上經(jīng)常看到說(shuō)不推薦使用StoryBoard或者Xib,推薦用純代碼手寫(xiě)。個(gè)人認(rèn)為這種觀點(diǎn)是和蘋(píng)果設(shè)計(jì)StoryBoard的初衷相悖的,在我做過(guò)的項(xiàng)目中是以StoryBoard為主,xib為輔,然后用代碼整合每個(gè)StoryBoard.
舉一個(gè)用Storyboard好處的例子就OK了,給控件添加約束,如果用Storyboard完成那是分分秒的事情,而用代碼的添加約束的話是何等的惡心,純代碼寫(xiě)的話會(huì)把大量的時(shí)間花在寫(xiě)UI上,而且技術(shù)含量是比較低的,這個(gè)個(gè)人認(rèn)為沒(méi)什么必要。在團(tuán)隊(duì)合作中負(fù)責(zé)UI開(kāi)發(fā)的小伙伴只需沒(méi)人負(fù)責(zé)一個(gè)Storyboard,各開(kāi)發(fā)各的,用SVN提交時(shí)把下面的勾(如下圖)去掉即可,這樣用Storyboard是沒(méi)有問(wèn)題的。然后再用代碼進(jìn)行整合就OK了。如果你在你的工程中加入了新的資源文件的話,用XCode自帶的SVN提交的話需要吧Project Setting文件一并提交。
三、實(shí)戰(zhàn)MVVM(用Xcode創(chuàng)建的Group是虛擬的文件夾,為了便于維護(hù),建議創(chuàng)建物理文件夾,然后再手動(dòng)引入)
1.下面通過(guò)一個(gè)實(shí)例來(lái)體會(huì)一下MVVM架構(gòu)模式,下面是該工程的一級(jí)目錄如下,每層之間的交互是用Block的形式來(lái)實(shí)現(xiàn)的
工程目錄說(shuō)明:
1.Request:文件夾下存儲(chǔ)網(wǎng)絡(luò)請(qǐng)求的類(lèi),下面會(huì)給出具體的實(shí)現(xiàn)
2.Config:就是工程的配置文件
3.Resource:就是工程的資源文件,下面有圖片資源和Storyboard文件資源
4.Tools是:工具文件類(lèi),存放工具類(lèi),比如數(shù)據(jù)正則匹配等。
5.Vender:存放第三方類(lèi)庫(kù)
6.Model:這個(gè)就不多說(shuō)了
7.ViewController:存放ViewController類(lèi)資源文件,也就是View層
8.ViewModel:存放各種業(yè)務(wù)邏輯和網(wǎng)絡(luò)請(qǐng)求
2.詳解Request:Request負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求的東西,具體如下:
NetRequestClass是存放網(wǎng)絡(luò)請(qǐng)求的代碼,本工程用的AF,因?yàn)楸竟こ讨皇且粋(gè)Demo,所以就只封裝了監(jiān)測(cè)網(wǎng)絡(luò)狀態(tài),GET請(qǐng)求,POST請(qǐng)求方法,根據(jù)現(xiàn)實(shí)需要,還可以封裝上傳下載等類(lèi)方法。
NetRequestClass.h中的代碼如下:
1 //
2 // NetRequestClass.h
3 // MVVMTest
4 //
5 // Created by 李澤魯 on 15/1/6.
6 // Copyright (c) 2015年 李澤魯. All rights reserved.
7 //
8
9 #import
10
11 @interface NetRequestClass : NSObject
12
13 #pragma 監(jiān)測(cè)網(wǎng)絡(luò)的可鏈接性
14 + (BOOL) netWorkReachabilityWithURLString:(NSString *) strUrl;
15
16 #pragma POST請(qǐng)求
17 + (void) NetRequestPOSTWithRequestURL: (NSString *) requestURLString
18 WithParameter: (NSDictionary *) parameter
19 WithReturnValeuBlock: (ReturnValueBlock) block
20 WithErrorCodeBlock: (ErrorCodeBlock) errorBlock
21 WithFailureBlock: (FailureBlock) failureBlock;
22
23 #pragma GET請(qǐng)求
24 + (void) NetRequestGETWithRequestURL: (NSString *) requestURLString
25 WithParameter: (NSDictionary *) parameter
26 WithReturnValeuBlock: (ReturnValueBlock) block
27 WithErrorCodeBlock: (ErrorCodeBlock) errorBlock
28 WithFailureBlock: (FailureBlock) failureBlock;
29
30 @end
NetRequestClass.m中的代碼如下:
1 //
2 // NetRequestClass.m
3 // MVVMTest
4 //
5 // Created by 李澤魯 on 15/1/6.
6 // Copyright (c) 2015年 李澤魯. All rights reserved.
7 //
8
9 #import "NetRequestClass.h"
10
11 @interface NetRequestClass ()
12
13 @end
14
15
16 @implementation NetRequestClass
17 #pragma 監(jiān)測(cè)網(wǎng)絡(luò)的可鏈接性
18 + (BOOL) netWorkReachabilityWithURLString:(NSString *) strUrl
19 {
20 __block BOOL netState = NO;
21
22 NSURL *baseURL = [NSURL URLWithString:strUrl];
23
24 AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL];
25
26 NSOperationQueue *operationQueue = manager.operationQueue;
27
28 [manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
29 switch (status) {
30 case AFNetworkReachabilityStatusReachableViaWWAN:
31 case AFNetworkReachabilityStatusReachableViaWiFi:
32 [operationQueue setSuspended:NO];
33 netState = YES;
34 break;
35 case AFNetworkReachabilityStatusNotReachable:
36 netState = NO;
37 default:
38 [operationQueue setSuspended:YES];
39 break;
40 }
41 }];
42
43 [manager.reachabilityManager startMonitoring];
44
45 return netState;
46 }
47
48
49 /***************************************
50 在這做判斷如果有dic里有errorCode
51 調(diào)用errorBlock(dic)
52 沒(méi)有errorCode則調(diào)用block(dic
53 ******************************/
54
55 #pragma --mark GET請(qǐng)求方式
56 + (void) NetRequestGETWithRequestURL: (NSString *) requestURLString
57 WithParameter: (NSDictionary *) parameter
58 WithReturnValeuBlock: (ReturnValueBlock) block
59 WithErrorCodeBlock: (ErrorCodeBlock) errorBlock
60 WithFailureBlock: (FailureBlock) failureBlock
61 {
62 AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] init];
63
64 AFHTTPRequestOperation *op = [manager GET:requestURLString parameters:parameter success:^(AFHTTPRequestOperation *operation, id responseObject) {
65 NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:nil];
66 DDLog(@"%@", dic);
67
68 block(dic);
69
70 } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
71 failureBlock();
72 }];
73
74 op.responseSerializer = [AFHTTPResponseSerializer serializer];
75
76 [op start];
77
78 }
79
80 #pragma --mark POST請(qǐng)求方式
81
82 + (void) NetRequestPOSTWithRequestURL: (NSString *) requestURLString
83 WithParameter: (NSDictionary *) parameter
84 WithReturnValeuBlock: (ReturnValueBlock) block
85 WithErrorCodeBlock: (ErrorCodeBlock) errorBlock
86 WithFailureBlock: (FailureBlock) failureBlock
87 {
88 AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] init];
89
90 AFHTTPRequestOperation *op = [manager POST:requestURLString parameters:parameter success:^(AFHTTPRequestOperation *operation, id responseObject) {
91 NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:nil];
92
93 DDLog(@"%@", dic);
94
95 block(dic);
96 /***************************************
97 在這做判斷如果有dic里有errorCode
98 調(diào)用errorBlock(dic)
99 沒(méi)有errorCode則調(diào)用block(dic
100 ******************************/
101
102 } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
103 failureBlock();
104 }];
105
106 op.responseSerializer = [AFHTTPResponseSerializer serializer];
107
108 [op start];
109
110 }
111
112
113
114
115 @end
3.詳解Config:創(chuàng)建pch文件,和Config.h文件
pch文件引入常用的頭文件,內(nèi)容如下:
1 //
2 // PrefixHeader.pch
3 // MVVMTest
4 //
5 // Created by 李澤魯 on 15/1/6.
6 // Copyright (c) 2015年 李澤魯. All rights reserved.
7 //
8
9 #ifndef MVVMTest_PrefixHeader_pch
10 #define MVVMTest_PrefixHeader_pch
11
12 #import"AFNetworking.h"
13 #import "UIKit+AFNetworking.h"
14 #import "Config.h"
15
16 #import "NetRequestClass.h"
17 #import "SVProgressHUD.h"
18 #endif
Config.h中就是各種宏定義和各種枚舉類(lèi)型和block類(lèi)型,代碼如下:
1 //
2 // Config.h
3 // MVVMTest
4 //
5 // Created by 李澤魯 on 15/1/6.
6 // Copyright (c) 2015年 李澤魯. All rights reserved.
7 //
8
9 #ifndef MVVMTest_Config_h
10 #define MVVMTest_Config_h
11
12 //定義返回請(qǐng)求數(shù)據(jù)的block類(lèi)型
13 typedef void (^ReturnValueBlock) (id returnValue);
14 typedef void (^ErrorCodeBlock) (id errorCode);
15 typedef void (^FailureBlock)();
16 typedef void (^NetWorkBlock)(BOOL netConnetState);
17
18 #define DDLog(xx, ...) NSLog(@"%s(%d): " xx, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
19
20 //accessToken
21 #define ACCESSTOKEN @"你自己的access_token"
22
23 //請(qǐng)求公共微博的網(wǎng)絡(luò)接口
24 #define REQUESTPUBLICURL @www.2cto.com"
25
26 #define SOURCE @"source"
27 #define TOKEN @"access_token"
28 #define COUNT @"count"
29
30 #define STATUSES @"statuses"
31 #define CREATETIME @"created_at"
32 #define WEIBOID @"id"
33 #define WEIBOTEXT @"text"
34 #define USER @"user"
35 #define UID @"id"
36 #define HEADIMAGEURL @"profile_image_url"
37 #define USERNAME @"screen_name"
38
39 #endif