模型的应用 && Xib &&代理模式的应用【应用管理】

来源:互联网 发布:劫持刘嘉玲的是谁知乎 编辑:程序博客网 时间:2024/04/29 18:35

模型

模型取代字典的好处

  • 使⽤用字典的坏处
    • ⼀一般情况下,设置数据和取出数据都使⽤用“字符串类型的key”,编写这些key时,编译器不会有任何友善提示,需要手敲。例如:
      dict[@"name"] = @"Jack";
      NSString *name = dict[@"name"];
    • 手敲字符串key,key容易写错 。Key如果写错了,编译器不会有任何警告和报错,造成设错数据或者取错数据。
  • 使⽤用模型的好处
    • 所谓模型,其实就是数据模型,专门⽤用来存放数据的对象,⽤用它来表⽰示数据会更加专业。
    • 模型设置数据和取出数据都是通过它的属性,属性名如果写错了,编译器会马上报错,因此,保证了数据的正确性。
    • 使⽤模型访问属性时,编译器会提供一系列的提⽰,提⾼编码效率。例如:
      app.name = @"Jack”;
      NSString *name = app.name;

字典转模型

  • 字典转模型的过程最好封装在模型内部
  • 模型应该提供⼀一个可以传⼊入字典参数的构造⽅方法
    • -(instancetype)initWithDict:(NSDictionary*)dict;
    • +(instancetype)xxxWithDict:(NSDictionary*)dict;
    • instancetype在类型表⽰上,跟id一样,可以表示任何对象类型
      instancetype只能用在返回值类型上,不能像id一样用在参数类型上
      instancetype比id多一个好处:编译器会检测instancetype的真实类型

构建一个模型类 App 来存储数据

//  App.h// 模型类:用来存放数据的类#import <Foundation/Foundation.h>@interface App : NSObject// 模型的名称@property (nonatomic, copy) NSString *name;// 模型的图标@property (nonatomic, copy) NSString *icon;// 通过字典来初始化模型对象- (instancetype) initWithDict:(NSDictionary *)dict;+ (instancetype) appWithDict:(NSDictionary *)dict;@end
//  App.m#import "App.h"@implementation App- (instancetype)initWithDict:(NSDictionary *)dict{    if(self = [super init]){        self.name = dict[@"name"];        self.icon = dict[@"icon"];    }    return self;}+ (instancetype)appWithDict:(NSDictionary *)dict{    return [[self alloc] initWithDict:dict];}@end

字典转模型的过程

这里写图片描述


Xib文件

Xib的创建及使用

  • Xib文件可以用来描述某一块局部的UI界⾯
  • 如何创建Xib文件
    • 首先创建一个继承UIView的自定义view。假如这个类叫:APPView。
    • 新建一个AppView.xib文件来描述AppView内部的结构。修改UIView的类型为AppView真实类型,即把AppView.xib文件的class 改成 AppView如下图所示:
      这里写图片描述
  • Xib文件的加载

    • 调用方法
      NSArray *objs = [[NSBundle mainBundle] loadNibNamed:@"AppView" owner:nil
      options:nil];
    • 这个方法会创建xib中的所有对象,并且将对象按顺序放到objs数组中。
      如果xib如下图所⽰,那么objs数组中依次会有3个对象:1个UIView、1个UILabel、1个UIButton
      这里写图片描述
    • 在开发阶段,面向开发者的是xib文件; 当把应用装到⼿机上时,xib⽂件就会转为nib⽂件

    使用xib封装一个自定义view的步骤

  • 1> 新建一个继承UIView的自定义view,假设类名叫做(AppView)
  • 2> 新建一个AppView.xib文件来描述MJAppView内部的结构
  • 3> 修改UIView的类型为AppView真实类型
  • 4> 将内部的子控件跟AppView进行属性连线
  • 5> AppView中创建一个模型属性
  • 6> 重写模型属性的set方法,因为在set方法中可以拿到外界传递的模型数据
  • 7> 把模型数据拆开,分别设置数据到对应的子控件中
  • 8> 补充:提供一个创建MJAppView的类方法,将读取xib文件的代码屏蔽起来

    Xib和storyboard对比

  • 共同点:
    • 都用来描述软件界面
    • 都用Interface Builder⼯具来编辑
  • 不同点
    • Xib是轻量级的,用来描述局部的UI界面
    • Storyboard是重量级的,用来描述整个软件的多个界面,并且能展⽰多个界面之间的跳转关系

源码

结构框架

这里写图片描述
这里写图片描述

代码

//  ViewController.h//#import <UIKit/UIKit.h>@interface ViewController : UIViewController@end
////  ViewController.m//#import "ViewController.h"#import "AppView.h"#import "App.h"@interface ViewController () <AppViewDelegate>@property (nonatomic, strong) NSArray *apps;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // 添加应用信息    // 1.总列数(一行最多3列)    int totalColumns = 3;    // 2.应用的尺寸    CGFloat appW = 90;    CGFloat appH = 90;    // 3.间隙 = (控制器view的宽度 - 3 * 应用宽度) / 4    CGFloat marginX = (self.view.frame.size.width - totalColumns * appW) / (totalColumns + 1);    CGFloat marginY = 40;    // 4.根据应用个数创建对应的框框(index 0 ~ 11)    for(int index = 0 ; index < self.apps.count; index++){        // 3.1 创建view,设置数据        AppView *appView = [AppView appViewWithApp:self.apps[index]];        // 3.2 把view的代理设置为控制器        appView.delegate = self;        // 3.3 添加view        [self.view addSubview:appView];        // 3.4 设置frame        int row = index / totalColumns;        int col = index % totalColumns;        // 计算x和y        CGFloat appX = marginX + col * (appW + marginX);        CGFloat appY = 40 + row * (appH + marginY);        appView.frame = CGRectMake(appX, appY, appW, appH);    }}// 点击下载按钮时就会调用- (void)appViewClickedDownloadButton:(AppView *)appView{    // 1.取出模型    App *app = appView.app;    // 添加标签    UILabel *tipLabel = [[UILabel alloc] init];    tipLabel.text = [NSString stringWithFormat:@"下载成功%@", app.name];    tipLabel.font = [UIFont systemFontOfSize:14];    tipLabel.textAlignment = NSTextAlignmentCenter;    tipLabel.textColor = [UIColor whiteColor];    tipLabel.backgroundColor = [UIColor blackColor];    tipLabel.frame = CGRectMake(0, 0, 170, 40);    tipLabel.center = CGPointMake(187.5, 300);    tipLabel.alpha = 0.0;    tipLabel.layer.cornerRadius = 5;    tipLabel.clipsToBounds = YES;    [self.view addSubview:tipLabel];    // 3.动画    [UIView animateWithDuration:1.0 animations:^{        tipLabel.alpha = 0.5;    } completion:^(BOOL finished) {        [UIView animateWithDuration:1.0 delay:1.0 options:UIViewAnimationOptionCurveLinear animations:^{            tipLabel.alpha = 0.0;        } completion:^(BOOL finished) {            [tipLabel removeFromSuperview];        }];    }];}- (NSArray *)apps{    if(_apps == nil){        // 初始化        // 1.获得plist的全路径        NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];        // 2.加载数组        NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];        // 3.将dictArray里面的所有字典转成模型对象,放到新的数组中        NSMutableArray *appArray = [NSMutableArray array];        for(NSDictionary *dict in dictArray){            // 3.1 创建模型对象            App *app = [App appWithDict:dict];            // 3.2 添加模型对象到数组中            [appArray addObject:app];        }        // 4.赋值        _apps = appArray;    }    return _apps;}@end
////  App.h// 模型类:用来存放数据的类#import <Foundation/Foundation.h>@interface App : NSObject// 模型的名称@property (nonatomic, copy) NSString *name;// 模型的图标@property (nonatomic, copy) NSString *icon;// 通过字典来初始化模型对象- (instancetype) initWithDict:(NSDictionary *)dict;+ (instancetype) appWithDict:(NSDictionary *)dict;@end
////  App.m//#import "App.h"@implementation App- (instancetype)initWithDict:(NSDictionary *)dict{    if(self = [super init]){        self.name = dict[@"name"];        self.icon = dict[@"icon"];    }    return self;}+ (instancetype)appWithDict:(NSDictionary *)dict{    return [[self alloc] initWithDict:dict];}@end
////  AppView.h//#import <UIKit/UIKit.h>@class App, AppView;// 声明一个协议@protocol AppViewDelegate <NSObject>@optional- (void)appViewClickedDownloadButton:(AppView *)appView;@end@interface AppView : UIView// 代理@property (nonatomic, weak) id<AppViewDelegate> delegate;// 数据模型@property (nonatomic, strong) App *app;// 创建模型+ (instancetype)appView;//通过模型数据来创建一个view+ (instancetype)appViewWithApp:(App *)app;@end
////  AppView.m//#import "AppView.h"#import "App.h"@interface AppView()@property (weak, nonatomic) IBOutlet UIImageView *iconView;@property (weak, nonatomic) IBOutlet UILabel *nameLabel;- (IBAction)download:(UIButton *)sender;@end@implementation AppView+ (instancetype)appViewWithApp:(App *)app{    NSBundle *bundle = [NSBundle mainBundle];    // 读取xib文件(会创建xib中的描述的所有对象,并且按顺序放到数组中返回)    NSArray *objs = [bundle loadNibNamed:@"AppView" owner:nil options:nil];    AppView *appView = [objs lastObject];    appView.app = app;    return appView;}+ (instancetype)appView{    return [self appViewWithApp:nil];}- (void)setApp:(App *)app{    _app = app;    // 1.设置图标    self.iconView.image = [UIImage imageNamed:app.icon];    // 2.设置名称    self.nameLabel.text = app.name;}// 下载按钮- (IBAction)download:(UIButton *)sender {    // 1.让按钮失效(文字变为“已下载”)    sender.enabled = NO;    [sender setTitle:@"已下载" forState:UIControlStateDisabled];    // 2.通知代理,download按钮被点击。    if([self.delegate respondsToSelector:@selector(appViewClickedDownloadButton:)]){        [self.delegate appViewClickedDownloadButton:self];    }}@end

代理模式

为什么要用代理模式

  • 我们要拿到控制器View,然后让它显示tipLabel,但是怎么拿到控制器View?
    • (1)将控制器View传到AppView.m里面,然后在download:方法调用,但这种方法非常不好,耦合性太强。
    • (2) 将按钮抛出去(放在AppView.h里面,这样控制器也可以监听),让控制器View监听,这样也不好。
    • 正确的方法是用代理模式,控制器作为AppView的代理。

对代理模式的分析

  • 当点击下载按钮的时候,应该通知控制器,控制器得知点击了下载按钮,就执行:添加tipLabel到控制器的View
  • 该做的事情应该交给该做的那个类去做(比较适合谁做的事情,就交给谁去做)。比如说我们要拿到控制器的view,添加一个label,谁能直接拿到控制器的view,就是控制器。所以我们得到一个结论,拿到控制器,添加lable的代码(操作),应该放到控制器里面。
  • 控制器要监听【AppView】内部下载按钮的点击,当下载按钮被点击了,会到download:方法,我们要在download:方法里面通知控制器(代理)([self.delegate appViewClickedDownloadButton:self];这个方法就是通知代理),下载按钮被点击,然后控制器把label添加到它的view上面上去。

达到效果

  • 点击下载按钮后变成不能点击的“已安装”
  • 中间慢慢弹出提⽰示:已经成功安装xxx,然后提⽰示会慢慢消失
    这里写图片描述 这里写图片描述
0 0
原创粉丝点击