zoukankan      html  css  js  c++  java
  • iOS开发UI篇—从代码的逐步优化看MVC

    iOS开发UI篇—从代码的逐步优化看MVC

    一、要求

    要求完成下面一个小的应用程序。

    二、一步步对代码进行优化

    注意:在开发过程中,优化的过程是一步一步进行的。(如果一个人要吃五个包子才能吃饱,那么他是否直接吃第五个,前面四个不用吃就饱了?)

    1.完成基本要求的代码(使用了字典转模型和xib连线)

    (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,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拿到模型数据后给内部的子控件设置对应的数据

    三、mvc机制简单说明

    说明:

    (1)在开发过程中,作为控制器处理的量级应该很轻,不该操心的不操心。协调好模型和视图就ok了,要学会当一个好老板。

    (2)三个部分各司其职,数据模型只负责数据的处理,视图部分只负责把拿到的数据进行显示,两个部分都是被动的,等待着大管家控制器的调遣。

    (3)在OC中,如果视图和数据模型之间有通道,那控制器是否处于失控状态呢?

  • 相关阅读:
    [置顶] 礼物:《红孩儿引擎内功心法修练与Cocos2dx》之结点系统(场景,层,精灵)
    略读六部计算机名著
    #Sam有话说#AI OR AXURE
    Android 鲜为人知的 8 个小秘密
    iphone下来电实现铃声静音
    mac下的svn工具——Versions使用详解
    android下面res目录使用
    状态压缩DP 题目小节 (一)
    [置顶] 【游戏产业的5年之变】
    /usr/bin/ld: cannot find lxxx问题总结
  • 原文地址:https://www.cnblogs.com/yipingios/p/5547634.html
Copyright © 2011-2022 走看看