zoukankan      html  css  js  c++  java
  • 字典转模型(国旗选择)

    "【案例: 国旗选择】"

    //此处插入国旗选择的图片

    》加载flags.plist数据到 "国旗模型[Flag.h]"

    》掌握代理【-(UIView *)pickerView:viewForRow:forComponent:reusingView:】的使用

    (1)在数据源里返回一组数据,行数由国旗个数决定

    (2)在代理方法中使用上面的方法,每一行返回一个View,返回的这个view为label

    (3)打印reusingView的地址和文字,"查看循环利用的view" --'备课的时候多演示几次'

    //eg: NSLog(@"==%p %@",label,label.text);

    (4)使用一个xib描述国家和国旗

    (5)掌握一个设置行高的代理方法

    ViewController.m 

    //

    //  ViewController.m

    //  02.国旗选择

    //

    //  Created by huan on 16/1/8.

    //  Copyright © 2016 huanxi. All rights reserved.

    //

     

    #import "ViewController.h"

    #import "FlagView.h"

    #import "Flag.h"

     

    @interface ViewController ()<UIPickerViewDataSource, UIPickerViewDelegate>

     

    @property (nonatomic, strong) NSArray *flags;

     

    @end

     

    @implementation ViewController

     

    -(NSArray *)flags//懒加载

    {

        if (!_flags) {

            _flags = [Flag flagList];

        }

        return _flags;

    }

     

    - (void)viewDidLoad {

        [super viewDidLoad];

        // Do any additional setup after loading the view, typically from a nib.

        NSLog(@"%@", self.flags);

    }

     

    // returns the number of 'columns' to display.

    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView

    {

        return 1;

    }

     

    // returns the # of rows in each component..

    - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

    {

        return self.flags.count;

    }

    #pragma mark 自定义PickView的行

    #warning UIPickerView循环引用在iOS7以后,不太明显,但是确实还是会循环引用,在iOS6,view的循环引用是非常明显

    -(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{

    //    //可以不设置frame,系统会设置

    //    UILabel *label = [[UILabel alloc] init];

    //    label.backgroundColor = [UIColor yellowColor];

    //    label.text = @"xx";

    //    return label;

        //如果有重用的view,会传一个view进来

        FlagView *flagView = (FlagView *)view;

        if (!flagView) {

            flagView = [FlagView flagView];

            //设置数据

            //获取模型

            Flag *flag = self.flags[row];

            flagView.flag = flag;

            //打印view的内存地址

            NSLog(@"row:%ld address: %p name: %@", (long)row, flagView, flag.name);

        }

        

    //#warning 一般设置自定义的View大小时,不直接设置bounds/frame

    // //自定义控件要添加bounds

    //    //设置高度无效

        flagView.bounds = CGRectMake(0, 0, 200, 0);

        return flagView;

        

    }

     

    #pragma mark 高度

    -(CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{

        return 50;

    }

     

    //#pragma mark 宽度

    //-(CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{

    //    return 200;

    //}

     

    - (void)didReceiveMemoryWarning {

        [super didReceiveMemoryWarning];

        // Dispose of any resources that can be recreated.

    }

     

    @end

     

    FlagView.h

    //

    //  FlagView.h

    //  02.国旗选择

    //

    //  Created by huan on 16/1/8.

    //  Copyright © 2016 huanxi. All rights reserved.

    //

     

    #import <UIKit/UIKit.h>

    @class Flag;

    @interface FlagView : UIView

    @property (weak, nonatomic) IBOutlet UILabel *nameLabel;

    @property (weak, nonatomic) IBOutlet UIImageView *imagView;

     

     

    +(instancetype)flagView;//为了获得xib的对象

     

    @property(nonatomic, strong)Flag *flag;

    @end

    //

    //  FlagView.m

    //  02.国旗选择

    //

    //  Created by huan on 16/1/8.

    //  Copyright © 2016 huanxi. All rights reserved.

    //

     FlagView.m

    #import "FlagView.h"

    #import "Flag.h"

     

    @implementation FlagView

     

    +(instancetype)flagView

    {

        return [[[NSBundle mainBundle] loadNibNamed:@"FlagView" owner:nil options:nil] lastObject];//因为xib的控件可以多拖几个,是同一级的

    }

     

    -(void)setFlag:(Flag *)flag{

        _flag = flag;

        self.nameLabel.text = flag.name;

        self.imagView.image = [UIImage imageNamed:flag.icon];

        

    }

     

    @end

    Flag.h

    //  Flag.h

    //  02.国旗选择

    //

    //  Created by huan on 16/1/8.

    //  Copyright © 2016 huanxi. All rights reserved.

    //

     

    #import <Foundation/Foundation.h>

     

    @interface Flag : NSObject

    /**

     *  copy :NSString

     strong :一般对象

     weakUI控件

     assign :基本数据类型

     */

     

    @property (nonatomic, copy) NSString *name;

    @property (nonatomic, copy) NSString *icon;

    //字典转模型 构造

     

    /**

     *  通过字典来初始化模型对象

     *

     *  @param dic  字典对象

     *

     *  @return 已经初始化完毕的模型对象

     */

    /*

     instancetype的作用,就是使那些非关联返回类型的方法返回所在类的类型!

     好处能够确定对象的类型,能够帮助编译器更好的为我们定位代码书写问题

     instanchetypeid的对比

     1、相同点

     都可以作为方法的返回类型

     

     2、不同点

     instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;

     

     instancetype只能作为返回值,不能像id那样作为参数,比如下面的写法:

     */

     

    //模型应该提供一个可以传入字典参数的构造方法

    /** 用字典实例化对象的成员方法 */

    -(instancetype)initWithDic:(NSDictionary *)dic;

     

    /** 用字典实例化对象的类方法,又称工厂方法 */

    +(instancetype)flagWithDic:(NSDictionary *)dic;

    /** plist加载对象数组 */

    +(NSArray *)flagList;

    @end

    //

    //  Flag.m

    //  02.国旗选择

    //

    //  Created by huan on 16/1/8.

    //  Copyright © 2016 huanxi. All rights reserved.

    //

    Flag.m

    #import "Flag.h"

     

    @implementation Flag

    -(instancetype)initWithDic:(NSDictionary *)dic{

        if (self = [super init]) {

            // 使用setValuesForKeys要求类的属性必须在字典中存在,可以比字典中的键值多,但是不能少。

            [self setValuesForKeysWithDictionary:dic];

        }

        return self;

    }

     

    +(instancetype)flagWithDic:(NSDictionary *)dic

    {

        return [[self alloc] initWithDic:dic];

    }

    //从处理plist中的数据 并返回模型对象的数组

    +(NSArray *)flagList

    {

        //加载plist model

        NSString *path = [[NSBundle mainBundle] pathForResource:@"flags" ofType:@"plist"];

        //加载数组

        NSArray *dicArray = [NSArray arrayWithContentsOfFile:path];

        //字典转模型

        NSMutableArray *tmpArray = [NSMutableArray array];

        for (NSDictionary *dic in dicArray ) {

            //创建模型对象 用字典实例化对象的工厂方法

            Flag *flag = [Flag flagWithDic:dic];

            //添加到对象到数组中

            [tmpArray addObject:flag];

        }

        return tmpArray;

    }

     

    二、字典转模型

    1.字典转模型介绍

    示意图:

     

    字典转模型的好处:

    (1)降低代码的耦合度

    (2)所有字典转模型部分的代码统一集中在一处处理,降低代码出错的几率

    (3)在程序中直接使用模型的属性操作,提高编码效率 

    (4)调用方不用关心模型内部的任何处理细节

    字典转模型的注意点:

    模型应该提供一个可以传入字典参数的构造方法

    - (instancetype)initWithDict:(NSDictionary *)dict;

    + (instancetype)xxxWithDict:(NSDictionary *)dict;

    提示:在模型中合理地使用只读属性,可以进一步降低代码的耦合度。

    补充内容:(KVC)的使用

    (1)在模型内部的数据处理部分,可以使用键值编码来进行处理

    复制代码
     1 - (instancetype)initWithDict:(NSDictionary *)dict
     2 {
     3     self = [super init];
     4     if (self) {
     5 //        self.answer = dict[@"answer"];
     6 //        self.icon = dict[@"icon"];
     7 //        self.title = dict[@"title"];
     8 //        self.options = dict[@"options"];
     9         
    10         // KVC (key value coding)键值编码
    11         // cocoa 的大招,允许间接修改对象的属性值
    12         // 第一个参数是字典的数值
    13         // 第二个参数是类的属性
    14         [self setValue:dict[@"answer"] forKeyPath:@"answer"];
    15         [self setValue:dict[@"icon"] forKeyPath:@"icon"];
    16         [self setValue:dict[@"title"] forKeyPath:@"title"];
    17         [self setValue:dict[@"options"] forKeyPath:@"options"];
    18     }
    19     return self;
    20 }
    复制代码

    (2)setValuesForKeys的使用

    上述数据操作细节,可以直接通过setValuesForKeys方法来完成。

    复制代码
    1 - (instancetype)initWithDict:(NSDictionary *)dict
    2 {
    3     self = [super init];
    4     if (self) {
    5         // 使用setValuesForKeys要求类的属性必须在字典中存在,可以比字典中的键值多,但是不能少。
    6         [self setValuesForKeysWithDictionary:dict];
    7     }
    8     return self;
    9 }
    复制代码

    三、补充说明

    1.readonly属性

     (1)@property中readonly表示不允许修改对象的指针地址,但是可以修改对象的属性。

     (2)通常使用@property关键字定义属性时,会生成getter&setter方法,还会生成一个带下划线的成员变量。

     (3)如果是readonly属性,只会生成getter方法,不会生成带下划线的成员变量.

    2.instancetype类型

    (1)instancetype会让编译器检查实例化对象的准确类型 
    (2)instancetype只能用于返回类型,不能当做参数使用

    3.instancetype & id的比较

    (1) instancetype在类型表示上,跟id一样,可以表示任何对象类型

    (2) instancetype只能用在返回值类型上,不能像id一样用在参数类型上

    (3) instancetype比id多一个好处:编译器会检测instancetype的真实类型

     
  • 相关阅读:
    java及前端请求跨域问题
    Node.js初级
    Oracle学习过程(随时更新)
    记录一下工作中犯的低级错误
    Maven管理项目架包
    使用Mybatis-Generator自动生成Dao、Model、Mapping相关文件
    position 定位属性
    一般处理程序 ashx 无法获取Session 值
    删除SQL SERVER 登录记录
    web.config 连接字符串 加密
  • 原文地址:https://www.cnblogs.com/Lu2015-10-03/p/5114402.html
Copyright © 2011-2022 走看看