iOS开发UI篇—字典转模型

一、能完成功能的“问题代码”

1.从plist中加载的数据

2.实现的代码

 1 //
 2 //  LFViewController.m
 3 //  03-应用管理
 4 //
 5 //  Created by apple on 14-5-22.
 6 //  Copyright (c) 2014年 heima. All rights reserved.
 7 //
 8 
 9 #import "LFViewController.h"
10 
11 @interface LFViewController ()
12 @property (nonatomic, strong) NSArray *appList;
13 @end
14 
15 @implementation LFViewController
16 
17 - (NSArray *)appList
18 {
19     if (!_appList) {
20 
21         // 1. 从mainBundle加载
22         NSBundle *bundle = [NSBundle mainBundle];
23         NSString *path = [bundle pathForResource:@"app.plist" ofType:nil];
24         _appList = [NSArray arrayWithContentsOfFile:path];
25         
26         NSLog(@"%@", _appList);
27     }
28     return _appList;
29 }
30 
31 - (void)viewDidLoad
32 {
33     [super viewDidLoad];
34     
35     // 总共有3列
36     int totalCol = 3;
37     CGFloat viewW = 80;
38     CGFloat viewH = 90;
39     
40     CGFloat marginX = (self.view.bounds.size.width - totalCol * viewW) / (totalCol + 1);
41     CGFloat marginY = 10;
42     CGFloat startY = 20;
43     
44     for (int i = 0; i < self.appList.count; i++) {
45 
46         int row = i / totalCol;
47         int col = i % totalCol;
48         
49         CGFloat x = marginX + (viewW + marginX) * col;
50         CGFloat y = startY + marginY + (viewH + marginY) * row;
51         
52         UIView *appView = [[UIView alloc] initWithFrame:CGRectMake(x, y, viewW, viewH)];
53       
54         [self.view addSubview:appView];
55         
56         // 创建appView内部的细节
57         // 0> 读取数组中的字典
58         NSDictionary *dict = self.appList[i];
59         
60         // 1> UIImageView
61         UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, viewW, 50)];
62         imageView.image = [UIImage imageNamed:dict[@"icon"]];
63         imageView.contentMode = UIViewContentModeScaleAspectFit;
64         [appView addSubview:imageView];
65         
66         // 2> UILabel
67         UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, imageView.bounds.size.height, viewW, 20)];
68         // 设置文字
69         label.text = dict[@"name"];
70         label.font = [UIFont systemFontOfSize:12.0];
71         label.textAlignment = NSTextAlignmentCenter;
72         
73         [appView addSubview:label];
74         
75         // 3> UIButton
76         // UIButtonTypeCustom和[[UIButton alloc] init]是等价的
77         UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
78         button.frame = CGRectMake(15, 70, viewW - 30, 20);
79         
80         [button setTitle:@"下载" forState:UIControlStateNormal];
81         // *** 不能使用如下代码直接设置title
82 //        button.titleLabel.text = @"下载";
83         // @property中readonly表示不允许修改对象的指针地址,但是可以修改对象的属性
84         button.titleLabel.font= [UIFont systemFontOfSize:14.0];
85         
86         [button setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];
87         [button setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateHighlighted];
88         
89         [appView addSubview:button];
90     }
91 }
92 
93 @end

3.实现效果

4.代码问题

在上述代码的第62,69行,我们是直接通过字典的键名获取plist中的数据信息,在viewController中需要直接和数据打交道,如果需要多次使用可能会因为不小心把键名写错,而程序并不报错。鉴于此,可以考虑把字典数据转换成一个模型,把数据封装到一个模型中去,让viewController不再直接和数据打交道,而是和模型交互。

一般情况下,设置数据和取出数据都使用“字符串类型的key”,编写这些key时,编辑器没有智能提示,需要手敲。如:

dict[@"name"] = @"Jack";

NSString *name = dict[@"name"];

手敲字符串key,key容易写错

Key如果写错了,编译器不会有任何警告和报错,造成设错数据或者取错数据

二、字典转模型

1.字典转模型介绍

示意图:

 

字典转模型的好处:

(1)降低代码的耦合度

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

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

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

字典转模型的注意点:

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

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

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

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

 

 2.代码示例(一)

新建一个类,用来作为数据模型

viewController.m文件代码(字典转模型)

#import "LFViewController.h"
#import "LFAppInfo.h"@interface LFViewController ()
@property (nonatomic, strong) NSArray *appList;
@end@implementation LFViewController// 字典转模型
- (NSArray *)appList
{if (!_appList) {// 1. 从mainBundle加载NSBundle *bundle = [NSBundle mainBundle];NSString *path = [bundle pathForResource:@"app.plist" ofType:nil];
//        _appList = [NSArray arrayWithContentsOfFile:path];
        NSArray *array = [NSArray arrayWithContentsOfFile:path];// 将数组转换成模型,意味着self.appList中存储的是LFAppInfo对象// 1. 遍历数组,将数组中的字典依次转换成AppInfo对象,添加到一个临时数组// 2. self.appList = 临时数组
NSMutableArray *arrayM = [NSMutableArray array];for (NSDictionary *dict in array) {//用字典来实例化对象的工厂方法
            [arrayM addObject:[LFAppInfo appInfoWithDict:dict]];}_appList = arrayM;}return _appList;
}- (void)viewDidLoad
{[super viewDidLoad];// 总共有3列int totalCol = 3;CGFloat viewW = 80;CGFloat viewH = 90;CGFloat marginX = (self.view.bounds.size.width - totalCol * viewW) / (totalCol + 1);CGFloat marginY = 10;CGFloat startY = 20;for (int i = 0; i < self.appList.count; i++) {int row = i / totalCol;int col = i % totalCol;CGFloat x = marginX + (viewW + marginX) * col;CGFloat y = startY + marginY + (viewH + marginY) * row;UIView *appView = [[UIView alloc] initWithFrame:CGRectMake(x, y, viewW, viewH)];[self.view addSubview:appView];// 创建appView内部的细节// 0> 读取数组中的AppInfo
//        NSDictionary *dict = self.appList[i];LFAppInfo *appInfo = self.appList[i];// 1> UIImageViewUIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, viewW, 50)];imageView.image = appInfo.image;imageView.contentMode = UIViewContentModeScaleAspectFit;[appView addSubview:imageView];// 2> UILabelUILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, imageView.bounds.size.height, viewW, 20)];// 设置文字label.text = appInfo.name;label.font = [UIFont systemFontOfSize:12.0];label.textAlignment = NSTextAlignmentCenter;[appView addSubview:label];// 3> UIButton// UIButtonTypeCustom和[[UIButton alloc] init]是等价的UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];button.frame = CGRectMake(15, 70, viewW - 30, 20);[button setTitle:@"下载" forState:UIControlStateNormal];button.titleLabel.font= [UIFont systemFontOfSize:14.0];[button setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];[button setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateHighlighted];[appView addSubview:button];button.tag = i;[button addTarget:self action:@selector(downloadClick:) forControlEvents:UIControlEventTouchUpInside];}
}- (void)downloadClick:(UIButton *)button
{NSLog(@"%d", button.tag);// 实例化一个UILabel显示在视图上,提示用户下载完成UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(80, 400, 160, 40)];label.textAlignment = NSTextAlignmentCenter;label.backgroundColor = [UIColor lightGrayColor];LFAppInfo *appInfo = self.appList[button.tag];label.text = [NSString stringWithFormat:@"下载%@完成", appInfo.name];label.font = [UIFont systemFontOfSize:13.0];label.alpha = 1.0;[self.view addSubview:label];// 动画效果// 动画效果完成之后,将Label从视图中删除// 首尾式动画,只能做动画,要处理完成后的操作不方便
//    [UIView beginAnimations:nil context:nil];
//    [UIView setAnimationDuration:1.0];
//    label.alpha = 1.0;
//    [UIView commitAnimations];// block动画比首尾式动画简单,而且能够控制动画结束后的操作// 在iOS中,基本都使用首尾式动画[UIView animateWithDuration:2.0 animations:^{label.alpha = 0.0;} completion:^(BOOL finished) {// 删除label
        [label removeFromSuperview];}];
}@end

模型.h文件代码

#import <Foundation/Foundation.h>@interface LFAppInfo : NSObject// 应用程序名称
@property (nonatomic, copy) NSString *name;
// 应用程序图标名称
@property (nonatomic, copy) NSString *icon;// 图像
// 定义属性时,会生成getter&setter方法,还会生成一个带下划线的成员变量
// 如果是readonly属性,只会生成getter方法,同时没有成员变量
@property (nonatomic, strong, readonly) UIImage *image;// instancetype会让编译器检查实例化对象的准确类型
// instancetype只能用于返回类型,不能当做参数使用- (instancetype)initWithDict:(NSDictionary *)dict;
/** 工厂方法 */
+ (instancetype)appInfoWithDict:(NSDictionary *)dict;@end

模型.m文件数据处理代码

 1 #import "LFAppInfo.h"
 2 
 3 @interface LFAppInfo()
 4 {
 5     UIImage *_imageABC;
 6 }
 7 @end
 8 
 9 @implementation LFAppInfo
10 
11 - (instancetype)initWithDict:(NSDictionary *)dict
12 {
13     self = [super init];
14     if (self) {
15         self.name = dict[@"name"];
16         self.icon = dict[@"icon"];
17     }
18     return self;
19 }
20 
21 + (instancetype)appInfoWithDict:(NSDictionary *)dict
22 {
23     return [[self alloc] initWithDict:dict];
24 }
25 
26 - (UIImage *)image
27 {
28     if (!_imageABC) {
29         _imageABC = [UIImage imageNamed:self.icon];
30     }
31     return _imageABC;
32 }
33 
34 @end

3.代码示例(二)

数据信息:plist文件

 

字典转模型(初步)

模型.h文件

 1 #import <Foundation/Foundation.h>
 2 
 3 @interface LFQuestion : NSObject
 4 
 5 @property (nonatomic, copy) NSString *answer;
 6 @property (nonatomic, copy) NSString *title;
 7 @property (nonatomic, copy) NSString *icon;
 8 @property (nonatomic, strong) NSArray *options;
 9 
10 @property (nonatomic, strong) UIImage *image;
11 
12 /** 用字典实例化对象的成员方法 */
13 - (instancetype)initWithDict:(NSDictionary *)dict;
14 /** 用字典实例化对象的类方法,又称工厂方法 */
15 + (instancetype)questionWithDict:(NSDictionary *)dict;
16 @end

模型.m文件

 1 #import "LFQuestion.h"
 2 
 3 @implementation LFQuestion
 4 
 5 + (instancetype)questionWithDict:(NSDictionary *)dict
 6 {
 7     return [[self alloc] initWithDict:dict];
 8 }
 9 
10 - (instancetype)initWithDict:(NSDictionary *)dict
11 {
12     self = [super init];
13     if (self) {
14         self.answer = dict[@"answer"];
15         self.icon = dict[@"icon"];
16         self.title = dict[@"title"];
17         self.options = dict[@"options"];
18 
19         [self setValuesForKeysWithDictionary:dict];
20     }
21     return self;
22 }

viewController.m文件中的数据处理

 1 - (NSArray *)questions
 2 {
 3     if (!_questions) {
 4     
 5         NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"questions.plist" ofType:nil]];
 6         
 7         NSMutableArray *arrayM = [NSMutableArray array];
 8         
 9         for (NSDictionary *dict in array) {
10             [arrayM addObject:[LFQuestion questionWithDict:dict]];
11         }
12         _questions=arrayM;
13     }
14     return _questions;
15 }

字典转模型(优化)

上面代码可以做进一步的优化,从plist文件中读取数据是可以交给模型去处理的,优化后代码如下:

模型.h文件

#import <Foundation/Foundation.h>@interface LFQuestion : NSObject@property (nonatomic, copy) NSString *answer;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *icon;
@property (nonatomic, strong) NSArray *options;@property (nonatomic, strong) UIImage *image;/** 用字典实例化对象的成员方法 */
- (instancetype)initWithDict:(NSDictionary *)dict;
/** 用字典实例化对象的类方法,又称工厂方法 */
+ (instancetype)questionWithDict:(NSDictionary *)dict;/** 从plist加载对象数组 */
+ (NSArray *)questions;@end

模型.m文件

 1 #import "LFQuestion.h"
 2 
 3 @implementation LFQuestion
 4 
 5 + (instancetype)questionWithDict:(NSDictionary *)dict
 6 {
 7     return [[self alloc] initWithDict:dict];
 8 }
 9 
10 - (instancetype)initWithDict:(NSDictionary *)dict
11 {
12     self = [super init];
13     if (self) {
14         self.answer = dict[@"answer"];
15         self.icon = dict[@"icon"];
16         self.title = dict[@"title"];
17         self.options = dict[@"options"];
18         
19         [self setValuesForKeysWithDictionary:dict];
20     }
21     return self;
22 }
23 
24 
25 + (NSArray *)questions
26 {
27     NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"questions.plist" ofType:nil]];
28     
29     NSMutableArray *arrayM = [NSMutableArray array];
30     
31     for (NSDictionary *dict in array) {
32         [arrayM addObject:[LFQuestion questionWithDict:dict]];
33     }
34     
35     return arrayM;
36 }
37 @end

viewController.m文件中的数据处理代码部分

1 - (NSArray *)questions
2 {
3     if (!_questions) {
4         _questions = [LFQuestion questions];
5     }
6     return _questions;
7 }

补充内容:(KVC)的使用

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

- (instancetype)initWithDict:(NSDictionary *)dict
{self = [super init];if (self) {
//        self.answer = dict[@"answer"];
//        self.icon = dict[@"icon"];
//        self.title = dict[@"title"];
//        self.options = dict[@"options"];// KVC (key value coding)键值编码// cocoa 的大招,允许间接修改对象的属性值// 第一个参数是字典的数值// 第二个参数是类的属性[self setValue:dict[@"answer"] forKeyPath:@"answer"];[self setValue:dict[@"icon"] forKeyPath:@"icon"];[self setValue:dict[@"title"] forKeyPath:@"title"];[self setValue:dict[@"options"] forKeyPath:@"options"];}return self;
}

(2)setValuesForKeys的使用

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

- (instancetype)initWithDict:(NSDictionary *)dict
{self = [super init];if (self) {// 使用setValuesForKeys要求类的属性必须在字典中存在,可以比字典中的键值多,但是不能少。
        [self setValuesForKeysWithDictionary:dict];}return self;
}

三、补充说明

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的真实类型

转载于:https://www.cnblogs.com/zengshuilin/p/5736534.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/254755.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Codechef:Path Triples On Tree

Path Triples On Tree 题意是求树上都不相交或者都相交的路径三元组数量。 发现blog里没什么树形dp题&#xff0c;也没有cc题&#xff0c;所以来丢一道cc上的树形dp题。 比较暴力&#xff0c;比较恶心 #include<cstdio> #include<algorithm> #define MN 300001 #de…

grbl

第一次发帖...之前上论坛都是查资料的&#xff0c;发现gcode这一块资料比较少先说一下Gcode:Gcode在工业控制上用的很多&#xff0c;是一种通用的控制指令&#xff0c;数控机床上经常用&#xff0c;在我diy雕刻机&#xff08;打印机之类的&#xff09;的时候要用到&#xff0c;…

mybitis实现增,删,改,查,模糊查询的两种方式:(2)

方式二&#xff1a;mapper代理接口方式 这种方式只需要xml接口&#xff08;不用写实体类&#xff09;但是需要符合三个规范 使用mapper代理接口方式在同一目录下&#xff08;可以创建一个源文件夹&#xff0c;达到类文件和xml文件分类的作用&#xff09;xml中namespace&#xf…

C语言中的静态函数的作用

转载 在C语言中为什么要用静态函数(static function)&#xff1f;如果不用这个static关键字&#xff0c;好象没有关系。那么&#xff0c;用了static以后&#xff0c;有什么作用呢&#xff1f;我们知道&#xff0c;用了static的变量&#xff0c;叫做静态变量&#xff0c;其意义是…

c++11 原子类型与原子操作

1、原子类型和原子操作&#xff08;1&#xff09;类型&#xff08;2&#xff09;操作&#xff08;3&#xff09;详述● 原子类型只能从其模板参数类型中进行构造&#xff0c;标准不允许原子类型进行拷贝构造、移动构造&#xff0c;以及使用operator等● atomic_flag 是一个原子…

依弗科(上海)机电设备有限公司

机器人喷涂倒计时&#xff0c;上帝帮我实现愿望吧 阿门 &#xfeff;&#xfeff;&#xfeff;&#xfeff;

CoDeSys

&#xfeff;&#xfeff;CoDeSys是全球最著名的PLC内核软件研发厂家德国的3S&#xff08;SMART&#xff0c;SOFTWARE&#xff0c;SOLUTIONS&#xff09;公司出的一款与制造商无关的IEC 61131-1编程软件。CoDeSys 支持完整版本的IEC61131标准的编程环境&#xff0c;支持标准的六…

使用halcon结合机械XY轴对相机进行9点标定

小哥哥小姐姐觉得有用点个赞呗&#xff01; 先在halcon中计算仿射变换矩阵并验证 //在图像中找到的模板中心位置 PicX:[1680.721,2065.147,911.499,526.798,1290.920,1285.731,1300.953] PicY:[968.321,964.366,976.283,980.035, 587.055,394.727,1355.487] //与图像中查找…

Ubuntu Linux 提出新的发布模式——测试周

2019独角兽企业重金招聘Python工程师标准>>> 导读开源技术项目最大的优势之一就是社区的每个人都可以自由地提出想法&#xff0c;如果获得社区支持&#xff0c;它可以变成现实。著名的 Ubuntu 开发人员 Simon Quigley 就提出了一个可能改变 Ubuntu Linux 开发过程的…

【转】小白级的CocoaPods安装和使用教程

原文网址&#xff1a;http://www.jianshu.com/p/e2f65848dddc 百度有很多CocoaPods的安装教程.第一次看的时候,确实有点摸不透的感觉.经过思考,一步一步来实践,前后花了三十几分钟,才顺利使用..所以想了想,我还是写一个小白级的教程吧.细到每一个细节都说明. 让你不用10分钟解决…

常见错误总结

少打头文件 少打using namespace std; 命名冲突&#xff0c;全局变量与局部变量命名一致&#xff0c;导致使用的值不是期望值 边读边写&#xff0c;导致改后读&#xff0c;覆盖写入的值 长整数移位溢出&#xff0c;1<<63是错误的&#xff0c;应该写成1ll<<63 循环变…

HALCON相机标定相机内参相机外参

目录相机标定1.相机标定是什么2.怎么使用halcon进行相机内外参标定&#xff1f;&#xff08;1&#xff09;搭建硬件1.**相机连好电脑&#xff0c;用相机厂家软件打开相机&#xff0c;检查一下相机是否正常。**2.**接下来使用halcon连接相机**&#xff08;2&#xff09;开始标定…

angular change the url , prevent reloading

http://stackoverflow.com/questions/14974271/can-you-change-a-path-without-reloading-the-controller-in-angularjs $location.search({vln: $scope.vln_id}, false);会改变url中 &#xff1f; 后面的 搜索参数&#xff0c;但是controller不会重新实例化。angular 官方文档…

C#圆形卡尺测量程序基于halcon

废话不多说上源码 觉得帖子有用给点个赞哈 先来个效果图 下边的是源码&#xff0c;自己新建一个文件粘贴进去&#xff0c;包含到您现在的项目 中。这串源码后边是使用方法。 using System; using System.Collections.Generic; using System.Linq; using System.Text; usin…

科维PLC运行时系统ProConOS embedded CLR 2.2 特定应用

ProConOS embedded CLR是新型的开放式标准化PLC运行时系统&#xff0c;符合IEC 61131标准&#xff0c;可执行不同的自动化任务&#xff08;PLC、PAC、运动控制、CNC、机器人和传感器&#xff09;。   通过采用国际标准的微软中间语言&#xff08;依据IEC/ISO 23271标准为MSIL…

set()与get()详细解答(C#)

这几天在搬砖时候用到了set()与get()&#xff0c;同事问了我一些问题&#xff0c;我打算在博客中总结一下。 觉得帮助到了您&#xff0c;帮我点个赞哦。 属性访问器 其实说白了就是操作一个属性&#xff0c;更通俗一点说就是对一个变量的取值与赋值。 先来看get() get 访问…

如何判断一条曲线是否自己相交?

今天看到群里有人在问这个问题&#xff0c;想了一个解决办法。 我们首先作假设&#xff0c;如果一条曲线有交点&#xff0c;那么它就是相交的对吧。可能大家想的都是这样&#xff0c;就开始找各种方法去识别交点。 我们换个角度想一下&#xff1a;是不是我们判断这条曲线是否带…

hdu 5813 Elegant Construction

水题 题意&#xff1a;有n个城市&#xff0c;给你每个城市能到达城市的数量&#xff0c;要你构图&#xff0c;输出有向边&#xff0c;要求无环&#xff0c;输出任意的解 例&#xff1a; Sample Input 332 1 021 143 1 1 0Sample OutputCase #1: Yes21 22 3Case #2: NoCase #3: …

halcon相机标定及图像矫正(代码)

侵删 1 halcon相机标定和图像矫正 对于相机采集的图片&#xff0c;会由于相机本身和透镜的影响产生形变&#xff0c;通常需要对相机进行标定&#xff0c;获取相机的内参或内外参&#xff0c;然后矫正其畸变。相机畸变主要分为径向畸变和切向畸变&#xff0c;其中径向畸变是由透…

函数参数的传递问题(一级指针和二级指针)

函数参数的传递问题&#xff08;一级指针和二级指针&#xff09; [转]原以为自己对指针掌握了&#xff0c;却还是对这个问题不太明白。请教&#xff01; 程序1&#xff1a; void myMalloc(char *s) //我想在函数中分配内存,再返回 { s(char *) malloc(100); } void …