iOS開發UI篇—從代碼的逐步優化看MVC

iOS開發UI篇—從代碼的逐步優化看MVC數組

1、要求mvc

要求完成下面一個小的應用程序。app

 

2、一步步對代碼進行優化ide

注意:在開發過程當中,優化的過程是一步一步進行的。(若是一我的要吃五個包子才能吃飽,那麼他是否直接吃第五個,前面四個不用吃就飽了?)優化

1.完成基本要求的代碼(使用了字典轉模型和xib連線)atom

(1)文件結構spa

(2)主要代碼code

  字典轉模型部分:orm

 YYappInfo.h頭文件blog

複製代碼

//
// YYappInfo.h
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface YYappInfo : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *icon;
@property(nonatomic,strong,readonly)UIImage *img;

-(instancetype)initWithDict:(NSDictionary *)dict;
/**工廠方法*/
+(instancetype)appInfoWithDict:(NSDictionary *)dict;
@end

 
 
複製代碼

YYappInfo.m文件

複製代碼

//
// YYappInfo.m
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import "YYappInfo.h"
@interface YYappInfo()
{
UIImage *_img;
}
@end
@implementation YYappInfo
-(instancetype)initWithDict:(NSDictionary *)dict
{
if (self=[super init]) {
self.name=dict[@"name"];
self.icon=dict[@"icon"];
}
return self;
}

+(instancetype)appInfoWithDict:(NSDictionary *)dict
{
return [[self alloc]initWithDict:dict];
}

-(UIImage *)img
{
_img=[UIImage imageNamed:self.icon];
return _img;
}
@end

 
 
複製代碼

 xib部分(YYappInfoView.h文件):

注:(xib視圖和YYappInfoView進行了關聯,三個屬性均進行了連線)  

複製代碼

//
// YYappInfoView.h
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface YYappInfoView : UIView
@property (strong, nonatomic) IBOutlet UIImageView *appInfoViewimg;

@property (strong ,nonatomic) IBOutlet UILabel *appInfoViewlab;
@property (strong, nonatomic) IBOutlet UIButton *appInfoViewbtn;

@end

 
 
複製代碼

主要功能實現部分:

YYViewController.m文件

複製代碼

//
// YYViewController.m
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import "YYViewController.h"
#import "YYappInfo.h"
#import "YYappInfoView.h"

@interface YYViewController ()
@property(nonatomic,strong)NSArray *apps;
@end

//開發思路
//1.加載plist文件(字典轉模型提供接口)
//2.使用xib文件完成單個的view
//3.計算座標,使用for循環把view展示到界面上
//4.優化代碼
@implementation YYViewController

//get方法,懶加載
-(NSArray *)apps
{
if (!_apps) {
NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil];
NSArray * arrayM = [NSArray arrayWithContentsOfFile:path];

NSMutableArray *appinfoarray=[NSMutableArray array];
for (NSDictionary *dict in arrayM) {
[appinfoarray addObject:[YYappInfo appInfoWithDict:dict]];
}
_apps = appinfoarray;
}
return _apps;
}

- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"%d",self.apps.count);

int totalloc = 3;
CGFloat appviewW = 80;
CGFloat appviewH = 90;
CGFloat margin = (self.view.frame.size.width-totalloc*appviewW)/(totalloc+1);

int count=self.apps.count;
for (int i = 0; i < count; i++) {
int row = i/totalloc;
int loc = i%totalloc;

CGFloat appviewX = margin + (margin + appviewW) * loc;
CGFloat appviewY = margin + (margin + appviewH) * row;

YYappInfo *appinfo=self.apps[i];

//拿出xib中的數據
NSArray *arryM=[[NSBundle mainBundle]loadNibNamed:@"appInfoxib" owner:nil options:nil];
YYappInfoView *appinfoview=[arryM firstObject];
//設置位置
appinfoview.frame=CGRectMake(appviewX, appviewY, appviewW, appviewH);
//設置值
appinfoview.appInfoViewimg.image=appinfo.img;
appinfoview.appInfoViewlab.text=appinfo.name;
//添加到視圖
appinfoview.appInfoViewbtn.tag=i;
[appinfoview.appInfoViewbtn addTarget:self action:@selector(Click:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:appinfoview];
}
}
-(void)Click:(UIButton *)btn
{
btn.enabled=NO;
YYappInfo *appinfo=self.apps[btn.tag];
UILabel *lab=[[UILabel alloc]initWithFrame:CGRectMake(60, 450, 200, 20)];
[lab setBackgroundColor:[UIColor lightGrayColor]];
[lab setTextAlignment:NSTextAlignmentCenter];
[lab setText:[NSString stringWithFormat:@"%@成功下載",appinfo.name]];
[self.view addSubview:lab];

lab.alpha=1.0;
[UIView animateWithDuration:2.0 animations:^{
lab.alpha=0;
}completion:^(BOOL finished) {
[lab removeFromSuperview];
}];
}
@end

複製代碼

2.對1進行優化(把數據呈現部分封裝到視圖)

說明:在1的基礎上尋找還會有那些能夠優化的部分

1)改進思路:

(1)1中主文件的66~67行對控件屬性的設置可否拿到視圖中進行?

(2)1中61~62行是從xib文件中讀取信息的操做,且和主控制器沒有什麼太大的關聯,可否把它也封裝到視圖中進行?

(3)當上述兩個步驟完成後,主文件69行之後的按鈕操做和按鈕單擊事件就顯得很突兀,放在主控制器中已經再也不合適,是否能夠把它放到視圖中進行處理

2)按照上述思路優化後的代碼以下:

  優化視圖,在視圖部分之對外提供一個接口,把數據的處理封裝在內部

YYappInfoView.h文件代碼:

複製代碼

//
// YYappInfoView.h
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import <UIKit/UIKit.h>
@class YYappInfo;
@interface YYappInfoView : UIView

//讀取
//+(instancetype)appInfoView;
//只對外開放一個數據接口
+(instancetype)appInfoViewWithappInfo:(YYappInfo *)appinfo;
@end

 
 
複製代碼

YYappInfoView.m文件代碼

說明:該文件中的屬性和click等均已作了連線的操做。

複製代碼

//
// YYappInfoView.m
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import "YYappInfoView.h"
#import "YYappInfo.h"
//私有擴展,把屬性拿進來
@interface YYappInfoView ()
@property (strong, nonatomic) IBOutlet UIImageView *appInfoViewimg;
@property (strong ,nonatomic) IBOutlet UILabel *appInfoViewlab;
@property (strong, nonatomic) IBOutlet UIButton *appInfoViewbtn;
@property(strong,nonatomic)YYappInfo *appinfo;

@end
@implementation YYappInfoView

+(instancetype)appInfoView
{
NSArray *arryM=[[NSBundle mainBundle]loadNibNamed:@"appInfoxib" owner:nil options:nil];
YYappInfoView *appinfoview=[arryM firstObject];
return appinfoview;
}

+(instancetype)appInfoViewWithappInfo:(YYappInfo *)appinfo
{
YYappInfoView *appInfoView=[self appInfoView];
appInfoView.appinfo=appinfo;
return appInfoView;
}

-(void)setAppinfo:(YYappInfo *)appinfoc
{
//這裏必定要記錄變化
_appinfo=appinfoc;
self.appInfoViewimg.image=appinfoc.img;
    self.appInfoViewlab.text=appinfoc.name;
}
- (IBAction)Click {

self.appInfoViewbtn.enabled=NO;
//YYappInfo *appinfo=self.apps[];

YYappInfo *appinfo=self.appinfo;
UILabel *lab=[[UILabel alloc]initWithFrame:CGRectMake(60, 450, 200, 20)];
[lab setBackgroundColor:[UIColor lightGrayColor]];
[lab setTextAlignment:NSTextAlignmentCenter];
[lab setText:[NSString stringWithFormat:@"%@成功下載",appinfo.name]];
//把lab添加到父視圖(即view中)
[self.superview addSubview:lab];

lab.alpha=1.0;
[UIView animateWithDuration:2.0 animations:^{
lab.alpha=0;
}completion:^(BOOL finished) {
[lab removeFromSuperview];
}];
}


@end

 
 
複製代碼

優化後的主控制器部分

YYViewController.m文件代碼

複製代碼

//
// YYViewController.m
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import "YYViewController.h"
#import "YYappInfo.h"
#import "YYappInfoView.h"

@interface YYViewController ()
@property(nonatomic,strong)NSArray *apps;
@end
@implementation YYViewController

-(NSArray *)apps
{
if (!_apps) {
NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil];
NSArray * arrayM = [NSArray arrayWithContentsOfFile:path];

NSMutableArray *appinfoarray=[NSMutableArray array];
for (NSDictionary *dict in arrayM) {
[appinfoarray addObject:[YYappInfo appInfoWithDict:dict]];
}
_apps = appinfoarray;
}
return _apps;
}

- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"%d",self.apps.count);

int totalloc = 3;
CGFloat appviewW = 80;
CGFloat appviewH = 90;
CGFloat margin = (self.view.frame.size.width-totalloc*appviewW)/(totalloc+1);

int count=self.apps.count;
for (int i = 0; i < count; i++) {
int row = i/totalloc;
int loc = i%totalloc;

CGFloat appviewX = margin + (margin + appviewW) * loc;
CGFloat appviewY = margin + (margin + appviewH) * row;

/*思路:
要達到的效果 appinfoview.appinfo=appinfo;
優化後即變成 appinfoview.appinfo=self.apps[i];
要進行上面代碼的操做,須要在視圖中新增長一個appinfo類的屬性,這樣數據——》視圖的轉換便可以不須要在主控制器中完成,讓程序結構一目瞭然
*/
YYappInfo *appinfo=self.apps[i];
YYappInfoView *appinfoview=[YYappInfoView appInfoViewWithappInfo:appinfo];
//設置位置
appinfoview.frame=CGRectMake(appviewX, appviewY, appviewW, appviewH);
//添加
[self.view addSubview:appinfoview];
}
}
@end

 
 
複製代碼

3.對2進一步優化(把數據處理部分拿到模型中去進行)

(1)思路:把字典轉模型部分的數據處理操做,拿到模型中去處理,這樣外界不須要再關心數據處理的內部細節。

(2)優化後的代碼以下

YYappInfo.h文件中向外開放一個接口,返回一個處理好的數組。

複製代碼

//
// YYappInfo.h
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface YYappInfo : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *icon;
@property(nonatomic,strong)UIImage *img;

-(instancetype)initWithDict:(NSDictionary *)dict;
/**工廠方法*/
+(instancetype)appInfoWithDict:(NSDictionary *)dict;
+(NSArray *)appinfoarray;
@end

 
 
複製代碼

YYappInfo.m文件中的數據處理

複製代碼

//
// YYappInfo.m
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import "YYappInfo.h"
@interface YYappInfo()
@end
@implementation YYappInfo
-(instancetype)initWithDict:(NSDictionary *)dict
{
if (self=[super init]) {
self.name=dict[@"name"];
self.icon=dict[@"icon"];
}
return self;
}

+(instancetype)appInfoWithDict:(NSDictionary *)dict
{
return [[self alloc]initWithDict:dict];
}

-(UIImage *)img
{
_img=[UIImage imageNamed:self.icon];
return _img;
}

//把數據處理部分拿到模型中來處理
+(NSArray *)appinfoarray
{
NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil];
NSArray * arrayM = [NSArray arrayWithContentsOfFile:path];

NSMutableArray *appinfoarray=[NSMutableArray array];
for (NSDictionary *dict in arrayM) {
[appinfoarray addObject:[YYappInfo appInfoWithDict:dict]];
}
return appinfoarray;
}
@end

 
 
複製代碼

主控制器中再也不須要關心數據處理的內部細節

YYViewController.m文件如今只是負責模型和視圖之間的協調工做了,怎麼樣?差很少了吧。

複製代碼

//
// YYViewController.m
// 12-視圖改進(1)
//
// Created by apple on 14-5-25.
// Copyright (c) 2014年 itcase. All rights reserved.
//

#import "YYViewController.h"
#import "YYappInfo.h"
#import "YYappInfoView.h"

@interface YYViewController ()
@property(nonatomic,strong)NSArray *apps;
@end
@implementation YYViewController

-(NSArray *)apps
{
if (!_apps) {
_apps=[YYappInfo appinfoarray];
}
return _apps;
}

- (void)viewDidLoad
{
[super viewDidLoad];

int totalloc = 3;
CGFloat appviewW = 80;
CGFloat appviewH = 90;
CGFloat margin = (self.view.frame.size.width-totalloc*appviewW)/(totalloc+1);

int count=self.apps.count;
for (int i = 0; i < count; i++) {

int row = i/totalloc;
int loc = i%totalloc;

CGFloat appviewX = margin + (margin + appviewW) * loc;
CGFloat appviewY = margin + (margin + appviewH) * row;

YYappInfo *appinfo=self.apps[i];
YYappInfoView *appinfoview=[YYappInfoView appInfoViewWithappInfo:appinfo];
appinfoview.frame=CGRectMake(appviewX, appviewY, appviewW, appviewH);
[self.view addSubview:appinfoview];
}
}
@end

 
 
複製代碼

實現效果:

 

4.補充說明

 View的封裝思路

(1) 若是一個view內部的子控件比較多,通常會考慮自定義一個view,把它內部子控件的建立屏蔽起來,不讓外界關心

(2) 外界能夠傳入對應的模型數據給view,view拿到模型數據後給內部的子控件設置對應的數據

3、mvc機制簡單說明

 

說明:

(1)在開發過程當中,做爲控制器處理的量級應該很輕,不應操心的不操心。協調好模型和視圖就ok了,要學會當一個好老闆。

(2)三個部分各司其職,數據模型只負責數據的處理,視圖部分只負責把拿到的數據進行顯示,兩個部分都是被動的,等待着大管家控制器的調遣。

(3)在OC中,若是視圖和數據模型之間有通道,那控制器是否處於失控狀態呢?

相關文章
相關標籤/搜索