一、点按钮,弹出的这个效果,这实际上是个Label, 这实际上是一个Label,点按钮弹出的这个效果, 设置一个Label的背景色、前景色、透明度、等等, 让它加进来,然后通过动画让它隐藏掉, 这就是,这个效果的实现思路, 咱们这个效果,先稍微往后放一放, 这个并不是重点, 接下来要做的一些东西,如果对于初学者来说,是有一些难度的, 那么这些难,难在哪儿了呢, 我们这里要做的是个什么功能呢, 要做的是,把刚才这个九宫格这个代码,刚才已经把它该做的已经做完了, 我们要做的是,把刚才这些代码封装一下, 封装,使用一个叫xib的东西,“叉爱必”的东西, 然后,同时,我们还要把这些代码做一些其他的封装, 就是做一系列的封装, 我们接下来写这些代码,写完以后这个效果还是这个效果, 只不过代码,要比之前看起来要好, 代码,做了更高级的封装处理, 这就是我们接下来要做的一系列的操作, 2.我们先来看一下我们这个代码, 我们这里是在viewDidLoad,当我们的控制器的view加载完毕以后,里面通过这一系列的内容,里面写一个循环,循环里面创建view,设置view的一些坐标,创建子控件,加到view里面,设置子控件的坐标、属性、数据,一个一个子控件设置,是不是在这个for循环里面有这么一堆的代码啊, 这么一堆的代码,写到for循环里面,大家觉得好不好, 觉得不爽对吧, 哪里不爽,有些同学说性能低,其实性能一点儿都不低,运行起来性能一点儿都不低, 对,可扩展性不强, 哪儿可扩展性不强,为什么可扩展性不强, 有同学说,再加一个按钮,那我直接把它改一下不就行了吗,我们数据里面,有几个数据啊, 数组里面,有几个数据啊, 现在我们数组里面,是不是有这么12条吧, 选中app.plist文件最后一个Dictionary,command + C、command + V,然后再运行,是不是又多出来一个按钮啊, 这个代码是有问题,问题也就是可扩展性的问题, 那么可扩展性,指什么问题, 其实这个代码,关键点在哪儿,关键点是这个代码没有达到我们的“可重用”, 没有达到“可重用”, 比如说,现在你这个控制器里面需要显示一个九宫格,是不是这一堆代码, 我又建了一个新的一个控制器,这个控制器里面,也要显示这么一系列的九宫格,这个时候怎么办,所有代码command + C、command + V,是不是直接拷过去,改一改, 是不是得这么做啊, 这叫代码的复制、粘贴,这叫代码的重用吗,不叫, 我们要想实现的是,当另外的一个控制器里面,也要显示九宫格的时候,直接把你这个类拿过来,直接就能用, 直接把你这个模块拿过来,调里面的某个方法,直接就能显示九宫格了, 是不是不需要把这个九宫格的代码从头儿再写一遍啊, 这就是这个代码的可重用性不强,换句话说,这个代码只能依赖于这个程序, 所以说,我们能不能把这个代码给它提取出来呢,所以,接下来,我们就说一下思路,怎么来提取这个代码: 二、提取这个九宫格代码: 1.告诉大家一个新的东西,就是xib文件,接下来,先告诉大家,这个xib是干什么的, 刚才大家有没有发现,每次创建一个控件,都要写这么一堆代码, 这样太繁琐了,我们要实现的效果是“所见即所得”,能不能实现这个效果,刚才我们发现,每一个应用是不是长的都是一样的啊,能不能在一个storyboard里先写把这3个控件(图片框、标签、按钮)拖出来,设置好坐标,然后呢,你把这个应用分别加载12次就ok了, 每一个应用的内容都是一样的,这些代码,我们通过可视化的方式,拖拉拽直接生成了,这样的话,就省的我去写代码了, 就是我想通过拖拉拽来生成这个控件,不需要去写代码了, 因为在一开始做iOS开发,所有的这些都要通过代码来实现,但是后来,为了提高开发效率,苹果就出了一个叫xib的东西,再后来,就又帮我们出了一个storyboard, storyboard,我们已经用过了吧,就是往里面去拖拉拽控件,这个效果吧, 也就是说,一开始有了xib,后面有了storyboard, 这两个东西产生的原因,就是为了一点:“提高我们的开发效率”, 你那些控件,不需要每次都通过代码来创建了,可以通过storyboard,xib,快速通过鼠标拖拉拽生成的,生成以后你就可以直接用这个东西了, 2.那么有人可能会问,storyboard、xib,这两个东西都是为了提高开发效率,都是通过拖拉拽生成控件, 换句话说,它们两个都是用来描述软件界面的, 软件界面长什么样儿,就是通过这两个东西描述, 你把控件拽上来,它会根据你这个界面,根据这个storyboard文件,或者根据你这个xib文件,后台会自动生成这些代码,后台也是通过代码实现的, 就不需要我们来写了,对吧, 那么既然它们俩个都是做这件事情的,那么它们俩个有什么区别呢, 注意,这个xib,它是一个轻量级的描述软件界面的文件, 这个storyboard,它是一个重量级的描述软件界面的文件, 什么是重量级、什么是轻量级的呢, 轻量级的xib,它是用来描述一些,比如说一个控制器局部的小View, 比如说,这个九宫格中,每个应用,是整个页面中这么一小块儿吧,这么一小块儿内容,可以使用xib, 比如说,我们要描述一个多个界面,多个界面是不是意味着有多个控制器啊, 从这个界面,一点就到另一个界面,再一点又到另外一个界面, 当你要描述多个界面的时候,多个控制器,以及每个界面的界面之间,还有什么关系,这种情况下,使用后面这个重量级的storyboard,来进行描述, 现在我们是要描述一个一个的屏幕界面吗,是要描述一个一个的手机界面吗,不是, 是不是只要描述一个界面里面的某一个内容吧, 这个时候就可以使用xib, 所以说,接下来我们用的时候,就通过这个xib来描述我们这么一个界面, 3.接下来,我们就要给大家介绍这么几个知识,一个就是我们这个xib, 使用xib精简代码: 1)什么是xib,xib能做什么, 用来描述软件界面的文件, 如果没有xib,所有的界面都需要通过代码来手动创建, 有了xib以后,可以在xib中进行可视化开发,然后加载xib文件的时候,系统自动生成对应的代码来创建界面, 与xib类似的还有storyboard文件, 2)xib与storyboard既然都是描述软件界面的,有什么区别吗, xib是轻量级的,一般只用来描述一个界面中的某部分内容(用来描述局部UI界面) storyboard是重量级的,一般用来描述软件的多个界面,以及不同界面之间的转换关系,换句话说,就是这个里面可以有多个控制器,并且还可以描述每个界面与每个界面之间的关系,跳转关系, 3)加载xib的方式: NSBundle *bundle = [NSBundle mainBundle]; [bundle loadNibNamed]; [bundle bundlePath]; 查看mainBundle的路径, 4)查找xib在手机模拟器中的位置,安装到手机上后就变成了nib文件了, /user/Steve/Library/Developer/CoreSimulator/Devices/0C63A035-071E-4EFC-8717-C387A3F7E026/data/Containers, NSString *home = NSHomeDirectory(); NSLog(@“%@”,home); 5)大家要清楚,无论是xib还是storyboard,这两个东西,最终都是生成代码的, 也就是说,最后还会生成一个一个创建代码, 创建控件那个代码,只不过这个代码不需要我们手动来写了, 在我们继续介绍xib和storyboard之前,给大家介绍一个相对简单的东西, 先把这个搞定以后,然后咱们就来开始说这个xib,用这个xib,来封装我们的界面, 好,接下来给大家说的是一个什么东西呢,就是我们这里列出来的,这个叫做“字典转模型”, 三、字典转模型, 1.先把这个说出来,这个是和我们的数据有关的, 为什么要把字典转成模型, 字典的缺陷: 1)“键”是字符串,如果写错了,编译器不报错(在编译的时候不报错),运行时可能出错,出错了很难找错, 2)使用“模型”可以更方便的使用面向对象的3大特性(封装、继承、多态)进行扩展, 3)什么是“模型”,模型就是自定义的类,通过为“类”增加各种属性来保存数据 4)字典转模型要修改哪里的代码, - 创建一个模型类, - 在懒加载的时候,把加载到的数据都放到模型类中,然后再把模型对象放到数组中, 复习:把app.plist转换成模型数组的过程,参考“字典转模型的过程” 把字典转模型的过程封装到“模型”内部, 原因:将来的这个“模型”可能会在很多地方被用到(比如有很多个控制器都会使用这个模型),那么每次用到模型的地方都需要写一次把字典中的数据赋 思路: 1)在模型中接受一个NSDictionary的参数,然后在模型内部把NSDictionary中的数据赋值给模型的属性, 2)封装一个initWithDict方法和一个appWithDict方法, 3.好,接下来我们就说一下这个“字典转模型”,这个是与咱们数据有关的,把这个说完以后,紧接着,就给大家说我们这个xib, 4.好,我说一下这个字典转模型,是个什么东西, 首先,大家想想,刚才咱们的程序中,哪里用到了字典, 是不是懒加载app.plist的时候,这里用到了字典了吧, - (NSArray *)apps{ if(_apps == nil){ //加载数据 //1.获取app.plist文件在手机上的路径 NSString *path = [[NSBundle mainBundle] pathForResource:@“app.plist” ofType:nil]; //2.根据路径加载数据, _apps = [NSArray arrayWithContentsOfFile:path]; } return _apps; } 我们把那些数据加载起来以后,这个apps数组里面,保存的就是字典了吧, 一个应用,对应的是不是就是一个字典数据, 那么接下来我们这里所说的“字典转模型”的意思,就是说, 把这个数组中,每一个字典,转成一个模型, 那么这个时候,大家可能会问,模型是什么, 首先,我们说,这个数组当中,存一个数据,用的是一个字典吧, 这个字典在这里的作用,就是为了,保存数据, 这个数组中的字典的作用,是不是就是为了保存数据, 字典里面有键值对,键值对,键对应的值,就是数据, 每一个键和值,也就是说,一个字典里面,可以有很多个键值对,是不是可以保存很多个数据吧, 比如说,你要描述一个人的信息,包含姓名、性别、年龄、身高、体重,一堆数据,这一堆数据怎么来存储,创建一个字典对象,在这个字典对象中,创建很多个键值对, 是不是就可以保存这个人的所有的数据了, 也就是说,字典,就是用来保存数据的, 那么我们这里要做的是,把字典转成模型, 这个模型的作用也是保存数据的, 那么什么是模型呢, 或者说,字典可以保存数据,模型怎么来保存数据呢, 比如说,一个字典中,有三个键值对, 姓名、性别、身高, 这是不是字典中的三个键值对啊, 意味着,这个字典中,保存着这3个数据吧, 那么,接下来,我想用另外一种方式来保存这个数据, 怎么保存呢,我可以这么做, 我可以新建一个Person类,Person里面有几个属性呢, 3个属性,这3个属性分别就是:姓名、性别、身高, 然后呢,我创建一个Person类的一个对象, 然后呢,为这个对象的这三个属性,name赋一个值,就是字典中键值对中的那个name键,对应的数据, 为这个Person对象的age属性,赋一个值, 为这个Person对象的height属性,赋一个值, 这3个值的来源,分别就是字典中的那3个键值对,的来源, 那3个键对应的值,来赋值, 那么这样的话,那个Person对象,这个就是个模型, 也就是说,你要存储一些数据,可以通过一个字典的方式,键值对的方式来存储, 也可以新建一个类,这个类中呢,有几个属性,就是字典中有几个键,就给它写几个属性, 然后呢,创建一个这个类的对象,然后把字典中键值对的值,分别设置给这个对象的每一个属性,这样的话,用一个这个对象,也可以表示一条数据, 和字典是不是一样的啊, 也就是说,这里接下来要给大家说的“字典转模型”的意思,就是说,把现在是用字典来存储数据,然后把这个字典,替换成一个一个的类的对象,用类的对象来保存数据, 明白我想干什么了吧, 3.然后大家想一想为什么要样做,这样做有什么好处, 等我们写完以后,看看到底有什么好处, 注意,以后的开发,都是用模型,不会用字典的, 所以说,这个你必须得掌握, 得熟练掌握, 我不相信你以后不会掌握,因为这个东西写的太多了,就好比说,你小的时候,你担心你长大了以后不会走路吗, 今天,先明白这个“字典转模型”的含义,是不是把一个字典,用一个类的对象来保存啊,把字典中的数据,不用字典来保存了,用一个类的对象来保存, 那么,它也是用来存数据的, 好,咱们先把这个实现了, 4.注意,我们现在既然要用一个类来表示一个字典中的数据, 那么,首先要怎么样, 首先要建一个类, 右键-〉New File -〉选中上面的iOS-〉选中Cocoa Touch Class -〉回车 -〉这个类叫什么啊, 注意,我们现在一个字典中,保存的是不是一个应用的数据,一个应用就是一个app,所以,我们这个模型,也可以把它叫做app,加个Test前缀,就叫TestApp类吧, 这个模型就继承自NSObject类, 然后呢,回车, 然后,接下来,我的问题是,这个类中有几个属性, 这个类中有几个属性,取决于当前你每个字典中有几个键值对, 每个字典中,是不是有两个键值对, 一个是name,一个是icon, 所以说,这个模型的属性,是不是也有两个啊, 这么模型中的属性的名字,建议一定要和字典中的键的名字是一样的, 字典中这个键叫name,这个模型中的属性也叫name, 字典中这个键叫icon,这个模型中的属性也叫icon, 当然你说我就写的不一样行不行,不一样也行,但是后面可能你就遇到麻烦了, 所以说,最好是起的一样, 所以说,现在我们就通过分析发现,这个模型中应该有几个属性啊,两个,第一个属性叫name,什么类型的,NSString类型,第二个属性叫icon,什么类型的,NSString类型, 所以说,模型会写了吗, #import <Foundation/Foundation.h> @interface TestApp:NSObject @property(nonatomic,copy)NSString *name; @property(nonatomic,copy)NSString *icon; @end 既然是NSString类型,对,所以说这儿用什么,用copy, 好,这两个属性是不是写好了, 到此为止,我们模型先写这么多,现在这个模型里面是不是有两个属性了, 可以用这个模型来保存数据了吧, 那么,接下来,注意看,现在我们在懒加载的时候,加载完毕,这个数组里面,是不是就是一个一个的字典, 我希望这个懒加载加载完毕以后,这个数组里面是一个一个的模型, 所以说,你这里能直接把它赋值给这个数组吗: _apps = [NSArray arrayWithContentsOfFile:path]; 你直接把它这个结果赋值给这个数组,这个数组里面,就变成一个一个的字典了吧, 所以说,我这里要先把这个字典的数据,是不是转成一个模型的数据以后,然后再赋值给这个_apps, 所以说,怎么做,注意看,我要改一下这个代码了, 我们现在这个模型是不是建好了, 在TestApp.h文件中: #import <Foundation/Foundation.h> @interface TestApp : NSObject @property(nonatomic,copy)NSString *name; @property(nonatomic,copy)NSString *icon; @end 在TestApp.m文件中: #import “TestApp.h” @implementation TestApp @end 在ViewController.m文件中: #import “ViewController.h” @interface ViewController () //1.加载app.plist的属性 @property(nonatomic,copy)NSArray *apps; @end @implementation ViewController //2.重写apps的getter方法,懒加载数组 - (NSArray *)apps { if(_apps == nil){ NSString *path = [[NSBundle mainBundle] pathForResource:@“app.plist” ofType:nil]; _apps = [NSArray arrayWithContentsOfFile:path]; } return _apps; } 模型建好了以后,我们在这里的代码就要实现,把这个数据转成模型, 注意,我先把这个数据加载起来, 加载起来以后,给它赋值给一个NSArray, //1.加载数据,获取app.plist文件在手机上的路径 NSString *path = [[NSBundle mainBundle] pathForResource:@“app.plist” ofType:nil]; //2.根据路径加载数据 NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path]; //arrayDict,为什么叫arrayDict,因为我们这个数组里面存的都是一个一个字典吧, //然后,我要把一个一个的字典,转成一个一个的对象,放到另外一个数组里面, //那么,既然要放到另外一个数组里面,是不是要向另外一个数组中一个一个的加对象啊, //所以说,另外一个数组就应该是一个什么,NSMutableArray吧, //应该是一个可变数组吧, //3.创建一个可变数组,用来保存一个一个的模型对象, //NSMutableArray arrayModels,里面是不是要用来保存一个一个的模型, //模型,我们就管它叫做Model,Models, //既然是一个可变数组,我们要用NSMutableArray, //一个空的可变数组, NSMutableArray *arrayModels = [NSMutableArray array]; //这,就表示创建了一个空的一个可变数组, //创建好空的可变数组以后,接下来要做的就是干什么呢,循环这个字典数组,arrayDict,把里面的每一个字典,创建一个对象,然后把这个对象,加到这个可变数组里面, //4.循环字典数组,把每个字典对象转换成一个模型对象, //因为我们这是一个数组,所以我们可以使用for循环,也可以使用for - in 循环吧, //这里大家喜欢用哪个,还是for - in ,吧,for - in 相对来说更简单一些, for (type *object in collection){ statements } //因为这个数组当中,arrayDict,每一个元素就是一个字典,所以说,我们这里面,可以设置一个什么,NSDictionary *dict, //然后,这里来一个arrayDict, for ( NSDictionary *dict in arrayDict){ statement } //这样的话,就表示循环这个字典数组,把里面的每一个字典,是不是赋值给这个字典变量*dict, //这样的话,这个dict是不是就是数组里面的每一个字典对象, //拿到这个字典对象以后,接下来,每次遇到一个字典对象,就要创建一个模型, //创建一个模型, //这个模型是不是就是我们刚才说的TestApp这个模型啊, //但是在这个地方,我们写TestApp,能访问到吗,根本访问不到, //原因是这里没有引入头文件,TestApp.h, //在最前面写上#import “TestApp.h”,引入TestApp的头文件, //这样的话,把这个头文件导入,这里就循环这个字典数组里面的每一个字典,每一个字典对应的创建一个模型对象, for (NSDictionary *dict in arrayDict) { //创建一个模型 TestApp *model = [[TestApp alloc] init]; //好,这样就创建好了这个模型,创建好这个模型以后,这个模型里面对应的那个属性,有数据吗,这个模型是不是空的啊, //model.name = 是不是要把字典中的name赋值给它,怎么写: model.name = dict[@“name”]; //字典中的name,是不是要赋值给这个模型, //字典中的icon,是不是也要赋值给这个模型, model.icon = dict[@“icon”]; //这样的话,这个模型里面,是不是就有这两个数据了,模型里面,就有这两个属性了, //然后,把这个模型怎么样,加到哪里,是不是加到可变数组里面, //把模型加到arrayModels中, [arrayModels addObject:model]; //这样的话,就把字典加到这个模型里面了,也就意味着,当这个for循环执行完毕以后,这个arrayModels,这个集合里面,是不是就已经保存了所有的模型对象了吧, //然后,我们直接让这个下划线apps等于这个arrayModels,_apps = arrayModels, _apps = arrayModels; //这样的话,当这个if语句执行完毕,这个apps里面,是不是有了所有的这些模型对象了吧, //然后,接下来,你再通过索引,拿到这个apps数组里面的任何一个对象,它还是一个Dictionary吗,不是了吧,里面每一个都变成什么,都变成模型了吧, 5.修改原来的代码: 然后,请问大家,我这里的代码是不是需要改一改了: - (void)viewDidLoad{ [super viewDidLoad]; int columns = 3; CGFloat viewWidth = self.view.frame.size.width; CGFloat appW = 75; CGFloat appH = 90; CGFloat marginTop = 30; CGFloat marginX = (viewWidth - columns * appW ) / (columns + 1); CGFloat marginY = marginX; for(int i=0;i<self.apps.count;i++){ NSDictionary *appDict = self.apps[i]; //我这个循环里面,这里的代码是不是需要改一改了, //这是不是一个数组,根据索引拿到数组里面每一个内容,还是字典吗,变成模型了吧,变成TestApp了, TestApp *appModel = self.apps[i]; //变成模型了以后,紧接着,下面的代码是不是也得改啊: //来,看看哪儿用到这个模型了, //设置图片框的数据: imgViewIcon.image = [UIImage imageNamed:appDict[@“icon”]]); //这儿,它既然不是字典,这儿是不是应该改成模型,字典是不是才根据键来取呢,模型这儿应该怎么写: //直接appModel.icon, //是不是直接这么写啊: imgViewIcon.image = [UIImage imageNamed:appModel.icon]; //大家想一想,你这么写,appModel.icon,和这么写,appDict[@“icon”],有什么区别吗, //第一,你通过字典去写的时候,appDict[@“icon”],这个icon是不是没有提示啊,你是不是得手动去写啊, //而你通过模型去写的时候,appModel.icon,这里是不是有提示, //第二,有很多同学,自己去写这个字典里的字符串键的时候,有很多时候会把这个写错,icon,这个会写成ioco,什么的, //这样的话,你写错以后,编译会有提示吗,不会, //编译根本没有错误提示,只有运行时候,才会因为没有这个键,才会出现意想不到的错误, //所以,变成模型的好处,第一:会有这个提示,第二:你这个地方,如果写错的话,你编译的时候,就会有错误提示了,比如,写错了,写成appModel.iocc,这样编译时就会把错误给检查出来了,是不是尽量降低我们程序运行的时候出现的错误吧,这是第二, imgViewIcon.image = [UIImage imageNamed:appModel.icon]; //第三,当你使用模型的时候,将来如果使用多个模型的时候,这个模型因为它是类嘛,就可以使用我们面向对象的继承、封装、多态了, //是不是可以使用其他的一些面向对象的特性啊, //例如,这个模型是这样的: #import <Foundation/Foundation.h> @interface TestApp:NSObject @property(nonatomic,copy)NSString *name; @property(nonatomic,copy)NSString *icon; @end //你可以把这个东西,自己再给它扩展,再继承,再给它封装,再给它多态,可以使用其他一些面向对象的特性啊, //但是用字典的话,不行,它仅仅是一个保存数据的工具, //所以说,字典转模型的好处: //第一,就是写代码的时候,有属性的提示, //第二,在编译的时候,如果写错了,会有错误提示,就会有编译错误,尽量减少运行时错误吧, //第三,使用模型,可以使用面向对象的各种各样的特征,可以让我们的程序变得更灵活, //这就是我们字典转模型的好处, //字典的缺陷,就是: //1)“键”是字符串,如果写错了,编译时不会报错,运行时会出现各种意想不到的错误, //2)使用“模型”,可以更方便的使用面向对象的3大特性(封装、继承、多态),进行扩展, //3)写代码的时候,字典的“键”,没有智能提示,但是模型的属性可以有智能提示, //这些都是它的一些好处,这些就是字典转模型的好处, //第一,就是有智能提示, //第二,就是编译时提示错误, //第三,就是可以使用面向对象的特性, //好了,我们接着来改代码吧,既然我们循环里面,获取到每一个数据的模型了, TestApp *appModel = self.apps[i]; //这儿用模型的icon, imgViewIcon.image = [UIImage imageNamed:appModel.icon]; //这儿也要把键改一下啊, //设置Label的数据(标题) lblName.text = appDict[@“name”]; //改成什么,模型.name, lblName.text = appModel.name; //还有哪儿,是不是没了,没了,就改了两个地方吧, //是不是这儿改了一个name,这儿改了一个icon吧, //我们再运行一下,command + R,是不是效果还是一样的啊, //ok,这就是我们这里这个字典转模型,大家明白字典转模型的意义了吗, //好,接下来,我们继续完善这个字典转模型,这个字典转模型还没完, 三、完善字典转模型, 1.刚才这么写没问题,但是这么写并不好,一般情况下,我们先说哪儿不好吧, 你这么转成模型,是没问题,但是,假如说我有10个地方都在用你这个模型,也就意味着,是不是有10个地方都在用这个字典转模型啊, - (NSArray *)apps{ if(_apps == nil){ //加载数据 //1.获取app.plist文件在手机上的路径 NSString *path = [[NSBundle mainBundle] pathForResource:@“app.plist” ofType:nil]; //2.根据路径加载数据, NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path]; //3.创建一个可变数组用来保存一个一个的模型对象, NSMutableArray *arrayModels = [NSMutableArray array];//一个空的可变数组 //4.循环字典数组,把每个字典对象转换成一个模型对象, for(NSDictionary *dict in arrayDict){ //创建一个模型, TestApp *model = [[TestApp alloc] init]; model.name = dict[@“name”]; model.icon = dict[@"icon]; //把模型加到arrayModels中 [arrayModels addObject:model]; } _apps = arrayModels; } return _apps; } 你这么转成模型,是没问题,但是,假如说我有10个地方都在用你这个模型,也就意味着,是不是有10个地方都在用这个字典转模型啊,是不是都要这样转一下,这样的话,你有10个地方都要去这么写, 每一个地方转模型的时候,是不是都要创建一个模型对象,把字典中的每一个键取出来,然后再设置给模型中的每一个属性吧, 是不是每一个地方都得这么写,那么大家想一下,我这个字典中,如果有10个键呢,有10个键值对呢, 这儿怎么办: TestApp *model = [[TestApp alloc] init]; model.name = dict[@“name”]; model.icon = dict[@“icon”]; 是不是写10次啊, 有100个呢,写100次吧, 大家觉得这是问题吗, 你写这个模型类,是不是不光是你自己用,将来也要有其他人要用吧, 你写这个模型,导致团队中其他人用这个模型的时候,都得把字典中的键,一个一个赋值给模型中的属性, 也就意味着,它有100个键值对,我用这个模型的时候,我得赋值100次啊, 怎么样在工作中,做一个让别人都受欢迎的同事呢, 不要给别人造成麻烦,这是最基本的,你这个工作如果总给别人造成麻烦,别人会喜欢你吗, 你如果写模型,想咱们刚才那样写,凡是用到这个模型的人,都得有多少个键值对,依次得赋值很多次啊, 你代码写完之后,应该想一想,这个代码别人用起来方便吗,如果不方便,能不能再封装一下呢, 这样的话,也就是说,我们要把这一块儿代码优化一下,不希望凡是用到我们这个模型的人,都要写很多遍赋值语句吧, TestApp *model = [[TestApp alloc] init]; model.name = dict[@“name”]; model.icon = dict[@“icon”]; 接下来,怎么改这儿,注意看: 我希望这个模型,有一个方法,initWithDict,把这个字典传进来, TestApp *model = [[TestApp alloc] initWithDict:dict]; 我希望我就这么一句话,把这个字典传给你这个模型,你模型的内部,去把这个字典里面的每一个键取出来,赋值给你这个模型的属性, 因为,模型中有多少属性,我知道吗,别人知道吗,别人也不需要知道, 模型里面有几个属性,是不是写模型的人最清楚了, 字典里面有几个属性,把字典给你,你内部去解析字典中的数据,依次赋值给你,模型里面的属性, 而我用的时候,对于我来说,我要用这个模型,我只需要创建一个模型对象,给你一个字典,然后你这个模型,就是一个充满数据的一个模型了, 我是不是就可以拿来用了, 这样的话,对于使用者来说,是不是非常非常的方便吧, 所以说,我就希望,你这个模型里面有一个initWithDictionary,这个方法, 别人只要给你一个字典,你内部会把字典解析,之后赋值给模型, 然后呢,我希望你还有另外一个方法,或许我不想这么做,这样做,还是麻烦, 我希望你有这么一个方法: TestApp *model = 类方法, TestApp *model = [TestApp 类方法, 来,总结一下, 1)NSString,它的类方法一般叫什么,stringWith什么什么吧, 这是它的类方法吧, 2)NSArray,它的类方法一般叫什么, arrayWith什么什么吧, 3)TestApp,它的类方法一般叫什么, appWith什么什么吧, 那个Test就没有了,NSString,那个NS是不是去掉了,NSArray,那个NS是不是也去掉了, NSString,它的类方法叫什么,stringWith,是不是前面的前缀去掉了吧, NSArray,它的类方法叫什么,arrayWith,是不是前面的前缀去掉了吧, 那我们TestApp,它的类方法叫什么,appWith,是不是也是把前缀去掉了吧, 那么,也就是说,我们起名的时候,我就不这么起名,我起个别的名儿行不行啊,行,是行的,但是你起这个名儿以后,你团队开发的时候,大家都是这个习惯,突然你习惯变了,是不是对谁都不好吧, 就是说,你既然就是在这个团队里面,你开发的时候,就遵守大家这个约定,这样的话,你开发的时候,会省事省力,听说过一句话,叫做“约定大于配置”吗,之前可能有同学是做Java开发,Java开发里,是不是到处都是配置啊,一堆繁琐的配置,有人说,很灵活,但是也有人说,很不爽,在.Net里面,配置没有Java那么多,.Net里面,都是叫“约定”,约定好我们都这么做,这就叫“约定”,约定大于配置,我们都约定好这么做以后,开发起来,就非常省事儿,非常快捷,省了很多很多配置,所以有句话叫做“约定大于配置”,苹果里面也是,我们有很多约定,这么约定,约定好以后,就这么做,这样的话,你如果不遵守这个约定,你会发现,各种各样的不爽,你遵守了这个约定,大家都爽了吧,大家好,才是真的好, 所以,我们这里,类方法的起名规则就是,把前缀去掉,把后面内容,app,加一个With什么什么, TestApp *model = [TestApp appWithDict:dict]; //然后,把字典传进来, //也就是说,我希望,你这个写模型的人,将来提供两个方法给我用, //1)一个是initWithDict, //2)一个是appWithDict, //将来我用的时候,只要调这两个方法,是不是就把字典传进去,内部你就帮我赋值了,是不是后面就不需要这么写了: //model.name = dict[@“name”]; //model.icon = dict[@“icon”]; //所以说,大家觉得,现在我们应该改造哪个类啊,是不是应该改造这个模型类TestApp,啊, //ok,给大家写两个方法, 在TestApp.h文件中: #import <Foundation/Foundation.h> @interface TestApp:NSObject @property(nonatomic,copy)NSString *name; @property(nonatomic,copy)NSString *icon; //给大家写两个方法, //1)一个,这个initWithDict,是一个对象方法, //用在TestApp *model = [[TestApp alloc] initWithDict:dict]; //2)一个,这个appWithDict,是一个类方法, //用在TestApp *model = [TestApp appWithDict:dict]; //返回类型,这儿该写个啥啊,我们是不是返回的这个类型啊,TestApp类型吧,我们先写这个,回头再给大家优化, - (TestApp *)initWithDict:(NSDictionary *)dict; + (TestApp *)appWithDict:(NSDictionary *)dict; //好,这样的话,是不是这两个方法有了, //你为什么这儿要写这个类型呢,TestApp *, //因为你看到它,最终是不是返回的就是这个类型自己啊, //所以说,我们这里就要返回这个类型啊, //好,实现一下这两个方法, //在TestApp.m文件中: #import “TestApp.h” @implementation TestApp - (TestApp *)initWithDict:(NSDictionary *)dict{ //在这里面,怎么写, //这个以前学过吗,首先判断if(self = [super init]){statement},调父类的init方法,是不是先把这个对象初始化一下, //我们说,在对象方法里面,self,是不是就表示当前对象自己啊, //因为这个类,是不是继承自Object那个类啊, //它是有父类的,先调这个父类的init方法,先把这个父类的成员都初始化完毕以后,赋值给这个self,然后接下来在这里,直接再return这个self, if(self = [super init]{ statement } return self; } //然后,在这个里面,为这个self的属性是不是赋值, if(self = [super init]){ self.name = dict[@“name”]; //self.name,字典里面怎么样,字典里面是不是取出这个name属性, self.icon = dict[@“icon”]; //self.icon,字典里面怎么样,字典里面是不是取出这个icon属性, } return self; } //这样的话,我们自己定义了一个新的initWithDict这个方法,在这个方法中,当这个对象初始化完毕以后,self = [super init]完毕以后,然后再把这个对象里面的这两个我们自己加的属性再初始化一次, //然后,接下来,当用户调完这个方法以后,返回了一个self,是不是就是一个已经充满数据的一个对象, //然后再实现这个类方法, + (TestApp *)appWithDict:(NSDictionary *)dict{ //在这里面咋写, return [self alloc] initWithDict:dict]; } //是不是ok了, //好,这是我们这两个,把这两个ok以后,我们这个模型这两个方法就写好了, @end 然后,在这里,我们这么一句话,是不是就搞定了: TestApp *model = [TestApp appWithDict:dict]; //是不是只要这么一句话,就把字典转换成模型了, //字典转模型,就一句话, //运行一下,可以了吧, //注意:以后大家写模型的时候,以后再写模型的时候, 1)第一,先把模型里面的属性写好, 2)第二,必须必须封装这两个方法, 如果不封装这两个方法,你这个模型,就是一个不合格的模型, 模型里面必备的,就是属性,以及initWithDict方法,和一个appWithDict方法, 一个是对象方法,一个是类方法, 这个是必备的,这是一套,以后大家写模型的时候,必须把这两个方法封装进去, 好了,这是我们字典转模型,给大家说的,