各種面向對象的編程中,都普遍使用MVC模式來嚴格地區分模型(Model)、視圖(View)和控制器(Controller)。如今回頭看看第一個本身編寫的程序-魔獸爭霸3資料查詢(https://github.com/DikeyKing/),有了一些些的MVC雛形:將XIB搭配出視圖(V),用控制器控制視圖還有數據之間的交互(C),數據寫成單獨的JSON(M)。五月份完工第一個APP到如今,如今看來,問題實在是太多了。控制器中仍是出現了太多關於JSON解析的代碼,變得臃腫(M和C分不開),隨處可見的objectForKey很是容易在key寫錯的時候直接崩潰(增長出錯機率)。沒有重用,模型就是被我寫成了JSON,而後直接在程序裏以JSON的形式被獲取…沒有對象的概念。以後在實習公司作了幾個項目,兩我的三個月開發四個應用,三個上架,一個連續三次被拒。雖然很快速地開發,可是代碼卻沒有達到預想,控制器中混亂不堪,處處都是JSON解析和網絡相關的操做------而這仍是已經使用了Story Board的狀況。html
以前是五分編程,兩分找bug和修改,兩分查資料,一分的學習。本身能夠靜下心來編程的時候,變成了三四分編程、六七分看書。可是卻能更好地構思代碼。想到這裏,想起阿里系的烏龍茶對我進行面試的時候和我說的話:企業是創造價值的地方,而不是來學習的地方。事實的確如此。乘着在學校的時候,我能夠專一於學習,用大量時間閱讀和深刻思考,畢業以後不會再有這樣的機會。固然,實習也是值得的,可是更重要的仍是那些沉澱下來的東西。git
回到主題。關於控制器的編寫,這幾天又在實踐上有了一些新的理解。依稀記得《iOS編程》(iOS Programming: The Big Nerd Ranch Guide)中關於評價的一段話,翻出來:一般狀況下,和編寫控制對象相比,編寫存儲對象的難度更高。大多數程序員能夠針對某個界面寫出控制器代碼並構建相應的XIB文件(不少人喜歡用純代碼,筆者比較喜歡Story Board,減小代碼量,讓代碼和視圖分的更開)。可是要寫出高質量的存儲對象,就須要程序員有必定的經驗,知道如何寫出既靈活又可靠的代碼,須要犯錯和修正的過程積累相關經驗。程序員
若是一個APP須要處理外部數據(網絡、相機、文件系統等等),那使用MVCS(Store)就會優於MVC。用本身在寫的東西做爲一個簡單的例子。github
在代碼沒有重構以前,登陸看起來是下面這個樣子的。面試
//ViewController.m
-(void)startLoginProgress { //發起鏈接 NSString *urlString = @"www.exampleURL.com"; AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; [manager.responseSerializer setAcceptableContentTypes:[NSSet setWithObject:@"text/html"]]; NSDictionary *parameters = @{@"forumType": @"", @"forumKey": @"", @"sdkType": @"1", @"packageName": @"com.mobcent.newforum.app82036", @"platType": @"5", @"appName": @"", @"email": @"", @"sdkVersion": @"2.0.0", @"password": @"" }; [manager POST:urlString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) { //得到數據 NSDictionary *dic = responseObject; //處理數據 if ([[dic objectForKey:@"rs"] boolValue] == 1) { [SVProgressHUD showSuccessWithStatus:@"登陸成功"]; } else{ [SVProgressHUD showSuccessWithStatus:@"登陸成功"]; } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@", error); }]; }
這段登陸主要作了三個工做,發起鏈接,得到數據,處理數據。可是實際上,做爲一個視圖控制器,根本不該該關心那麼多,視圖控制器只管兩件事情,點擊發起登陸,而後將結果告訴用戶。編程
重構後視圖控制器中的代碼:緩存
//發起登陸,只關心登陸結果。徹底不關注登陸的過程。
//ViewController.m
[[JHRESTEngine sharedJHRESTManager] loginWithCompletion:^(NSError *err) { if (err ==nil) { if ([[JHUserDefaults getLoginState] isEqualToString:@"YES"]) { [SVProgressHUD showSuccessWithStatus:@"登陸成功"]; [self dismissViewControllerAnimated:YES completion:^{ }]; }else{ [SVProgressHUD showErrorWithStatus:@"密碼錯誤"]; } }else{ [SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:@"%@",err]]; } }]; //登陸的細節(獲取API,發起鏈接,處理返回數據) //RESTEngine.m -(id)loginWithCompletion:(void (^)(NSError *))block{ [self POST:kJHLoginURLString parameters:[JHForumAPI getParameterDic:GET_LOGIN] success:^(AFHTTPRequestOperation *operation, id responseObject) { NSDictionary *dic = responseObject; if ([[dic objectForKey:@"rs"] isEqual: @1]) { [JHUserDefaults saveLoginState:@"YES"]; block(nil); }else{ [JHUserDefaults saveLoginState:@"NO"]; block(nil); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { block(error); }]; return self; } //API.m +(NSDictionary *)getParameterDic:(int)getParameter { //具體代碼 }
代碼看上去好像還複雜了一些,這是由於例子很是的簡單。這個過程當中,登陸的細節只包含了獲取API,鏈接發起,處理返回數據,考慮更復雜的狀況,若是有大量的相似操做的一個客戶端,擁有數十個相似訪問的API。放在不同的文件對於後期的維護和更新顯然是困難的。正常的應用還要考慮將返回的數據處理成對應的對象供控制器去展示(這個過程當中沒有體現)。想要更好的用戶體驗,還須要一代塊關於緩存的代碼。這些操做若是所有都在視圖控制器中而不分離出去,會致使ViewController的臃腫和失控。網絡
若是項目還處於初期,並且會愈來愈複雜,那就儘可能考慮考慮將關於存儲的(Store)代碼分離出去吧。少許的操做,換來的確是更清晰更易讀的代碼和更好的可維護性。app