一、展示汽车品牌数据 1.首先,我们还是先把控制器调成3.5英寸,再把模拟器调成iPhone4S, 2.然后呢,我们要先把素材拷进来, 我们要展示,要把一个plist文件中的数据展示到我们的这个UITableView里面,所以说,首先,是要把我们的plist文件拷进来, 找到我们这个plist文件,cars_simple.plist, 3.把这个cars_simple.plist文件,拖到Supporting Files下面, 首先,看一下这个plist文件,整体是个什么,整体是个Array吧, 整体是个数组, 里面每一个元素,又是一个什么,又是一个字典, 每个字典里面包含哪些键值对, 是不是3个键值对,一个描述desc、一个标题title、一个是具体里面的车的品牌吧,车的品牌cars, 4.整体这个plist文件,就是对汽车品牌的一个归类,第一个元素就是德系品牌, 这个组的标题,就是德系品牌, 也就意味着,这个组的标题,要显示在这个组的上面,这个组的描述,要显示在这个组的下面,这个组的具体品牌,要显示在中间, 再看第二组,是日韩品牌, 二、懒加载 1.所以我们第一步,把这个plist文件,加载到我们的内存里面,是不是要把字典转换成模型啊, 因为我们之前已经学过了,把字典转模型了,所以说,我们第一步,懒加载,加载数据, 2.我们是不是要先写个模型啊, 要根据我们这个字典,要先写个模型, 所以说,我们现在要懒加载,把这个数据加载到模型里面,不是加载到字典里面,所以说,第一步,要先写一个模型, 写模型的时候,我们看一下这个字典,这个字典里面有三个键值对吧, 所以说,这个模型里面,应该有几个属性,有三个属性吧, 所以说,先建一个模型,这个模型叫什么,前缀来个Test吧,注意,这个模型不叫car,我们这儿是个分组,这么一条记录,是不是表示一组数据啊,一组数据,有组标题,有组描述,以及组里面具体的信息, 所以说,这个应该是个组吧,每一个元素应该是个组,对吧,每个元素应该是个组,这个组里面有三个属性, 应该是个组,对,Group, 好,点击Next,建立模型, 这个模型里面,应该有三个属性,我们说,属性的名字,应该和字典里面的“键”的名字一致吧, 所以,第一个属性是title、第二个属性是desc,这两个都是字符串类型, 第三个属性,是个什么类型,Array吧,所以,第三个属性是cars,是个NSArray类型, 第一个属性是什么,组标题,第二个属性是什么,组描述,第三个属性是什么,组里面具体的汽车品牌吧, //组标题 @property(nonatomic,copy)NSString *title; //组描述 @property(nonatomic,copy)NSString *desc; //这组里面的汽车品牌信息 @property(nonatomic,strong)NSArray *cars; 是不是有三个这么个属性, 3.我们说,新建模型的时候,除了把这个属性写完,还得封装什么方法,是不是还得封装两个方法, 封装两个快速根据字典创建模型的方法, 我们先看第一个,返回值类型是什么,instancetype吧, -(instancetype)initWithDict:(NSDictionary *)dict; 我们再看第二个 -(instancetype)叫做……要以类的名称开头吧,类的名称去掉前缀,是什么,Group吧,所以要以group开头 - (instancetype)groupWithDict:(NSDictionary *)dict; 好,放上这两句话,然后把这两个方法实现一下, 4.把这两个方法实现一下, 这儿怎么写, - (instancetype)initWithDict:(NSDictionary *)dict{ if(self = = [super init]){ statements } } 如果self = = [super init] ,是不是调用首先要调用父类的init方法,把返回值设置给这个self, 然后接下来,我们最后要返回这个self啊, 然后在这个里面,所以在这个里面,需要把字典里面的每一个键值对依次赋值给我们的每一个属性啊, 我们是不是这样依次就把字典里面的每一个键对应的值取出来,然后分别赋值给了这个对象的每一个属性吧, OK,告诉大家,从今天开始,我们不再这么写了, 大家先记住这种写法吧,等会儿咱们再给大家详细说这种写法, 这样写,如果说这个字典里面有是个属性,你这儿是不是得写十句代码,如果有一百个属性,你这儿是不是得写一百句代码, 这样写太费劲了,告诉大家一个更简单的办法,无论他里面有多少个属性,一句话搞定, 无论里面有多少个属性,一句话搞定, 怎么写呢,self,有一个叫做setValues,用最后一个,这个,setValuesForKeysWithDictionary void setValuesForKeysWithDictionary:(NSDictionary *) [self setValuesForKeysWithDictionary:dict]; 把字典传进来, 就是一句话,这句话的意思就是这句话,第一,就相当于这三句话: self.title = dict[@“title”]; self.desc = dict[@“desc”]; self.cars = dict[@“cars”]; 它内部会分别把字典中的每一个键对应的值取出来,然后把这个值分别设置给这个 这个对象的对应的和这个键的名字一样的属性, 这个时候如果说你这个对象的属性的名字和这个键的名字起的不一样,这个时候就不行了, 所以说,为了能保证这么用,我们一定要把这个属性的名字和键的名字一定要起的一样了,明白吗, 这种就是调用了我们KVC里面的方法, 5.封装完这个方法以后,接下来,是不是要封装另外一个方法了,那个类方法, + (instancetype)groupWithDict:(NSDictionary *)dict{ return [[self alloc] initWithDict:dict]; } 这样的话,这个模型就封装好了, 这些都封装好了以后,该写什么了,是不是该写懒加载了吧, 四、懒加载 1.要实现懒加载,首先,我们这里要有一个属性, 这个属性是NSArray类型吧,因为里面是不是分了很多很多组数据,所以说,这个名称起什么,是不是groups啊,groups,然后这里就开始懒加载这些数据, 先写一个分段标记,#pragma mark - 懒加载数据 这样,在方法的下拉列表里,找这个方法的时候,就好找一点了吧, 然后怎么写,是不是重写groups的getter方法啊, - (NSArray *)groups{ //然后,在里面怎么判断, if(_groups = = nil) { // 说明里面没有数据,如果没有数据,在这里面懒加载,对吧, //懒加载的数据,然后最后怎么办,是不是返回这个_groups,就OK了吧, } return _groups; } 然后在这里面懒加载这个数据, if(_groups = = nil) { 1)第一步,获取这个plist文件的路径, 2)第二步,加载, 3)第三步,把字典转成模型, 4)第四步,赋值, 5)第五步,最后一步,返回, 第一步,就是找到plist文件的路径,怎么找这个路径, if(_groups = = nil ) { NSString *path = [[NSBundle mainBundle] pathForResource:@“cars_simple.plist” ofType:nil]; 这样就返回这个plist文件的路径了吧, 然后,紧接着,干什么,加载plist文件,怎么加载啊, NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path]; 注意看,这个plist文件,整体是个啥,是个Array类型吧,所以怎么加载, 里面加载的是不是都是字典的这个array啊,等于什么, [NSArray arrayWithContentsOfFile:path]; 这样就把plist文件中的数据是不是加载到这个数组里面了,因为这个plist文件原来,每一个数组元素都是一个字典,所以说,在这个arrayDict的这个数组里面是不是保存的也是一个一个的字典, 我们接下来就是把字典转成模型吧, 怎么转,是不是首先得有一个模型的一个数组, NSArray,但是这个模型数组是不是要一条一条往里面加,所以说,这个应该是用什么, NSMutableArray, NSMutableArray *arrayModel = 然后怎么写, NSMutableArray *arrayModel = [NSMutableArray array]; 创建这么一个空的模型数组吧, 遍历字典数组中的每个字典,把每个字典转成模型,把模型放到arrayModel数组中, 怎么遍历,用什么来遍历,for-in来遍历, 遍历的每一个就是什么,Dictionary吧, 这里是哪里,arrayDict, for(NSDictionary *dict in arrayDict){ //然后里面怎么办,是不是创建模型对象, } 我们这里能访问到模型对象吗,访问不到的原因是什么,没有引入头文件吧, 叫什么“TestGroup.h”吧,#import “TestGroup.h” 然后,里面怎么写, TestGroup *model = [TestGroup groupWithDict:dict]; 是不是直接这么写,这样是不是就创建好模型,然后模型里面也有数据了吧,然后,怎么办, arrayMode addObject,是不是把这个model加进来, [arrayMode addObject:model]; 这样的话,把模型是不是加到这个数组里面了吧, 最后,我们在这里,让这个下划线groups,等于这个arrayModel, _groups = arrayModel; 这样是不是这个懒加载就OK了吧,懒加载就OK了, 6.懒加载写完以后,紧接着,我们数据都有了,UITableView控件也有了, 接下来,就该怎么办了, UITableView还没有呢, 四、创建UITableView控件, 1.我们只是有数据了,接下来,我们要做的就是,拽一个UITableView,然后设置数据源对象,实现数据源协议里面的方法,然后在这些方法中使用我们刚才懒加载起来的这些数据, 把数据返回给UITableView,就OK了吧, 2.然后,我们拽一个UITableView, 然后设置数据源对象,给这个控制器, 然后,控制器要作为UITableView的数据源对象,所以说,控制器要怎样, 遵守数据源协议吧, 要显示数据,是不是要让控制器实现那三个基本的数据源方法啊, 3.实现三个基本的数据源方法, 再写一个#pragma mark - #pragma mark - 数据源方法 1)第一个数据源方法,是不是返回多少组的方法吧,叫什么, (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 大家告诉我,这里有几组数据啊, 刚才懒加载,你这个字典中懒加载,加载了多少个,这个group,是不是就有几组数据啊, 刚才是不是把所有这些数据都加载到我们这个groups这个数组里面了,所以说,这里面有几个对象,它就有几组数据, 所以说,是不是返回self.groups.count,是不是返回这个啊, - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return self.groups.count; } 2)然后接下来,第二个数据源方法就是,每一组有几行, 不如说,这组,这组里面有几条数据, 是不是取决于这组里面这个cars里面有几个,有几个内容啊, 所以说,我们是不是要先获取这一组,然后再获取这个组的cars,再“点”它的count啊, 所以说,每一组有几行,那个数据源方法,叫什么, - (NSInteger)numberOfRowsInSection吧, - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ } 这个是不是当前那个组啊, 所以说,第一步,根据索引,获取当前那个组对象, 根据组索引,组索引指的是谁, section, 获取组对象,组对象叫什么,TestGroup, TestGroup *group = self.groups,是不是所有组都在这个里面, TestGroup *group = self.groups[section]; section是不是根据组的索引获取到这个组对象了, 这个section是不是当前组的索引, groups,是不是所有组都在这个集合里面, 我们在这个集合里面,根据这个索引,是不是拿到当前这个组了, 拿到这个组以后,我们是不是要返回,这个组里面有多少条数据吧, 这个组里面有多少条数据,取决于什么, 这个组里面是不是有cars这个数组,cars这个数组里面有多少条数据,就是这个组里面应该显示多少条数据吧, - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ //1.根据组索引(section)获取组对象 TestGroup *group = self.groups[section]; //是不是所有组都在这个self.groups里面, //self.groups[section],这是不是根据组索引获取组对象了, return groups.cars.count; } section:是当前组的索引, groups:所有组都在这个集合里面, 我们在这个集合里面,根据那个索引,拿到当前对应的这个组了, 拿到这个组以后,我们要返回这个组里面有多少条数据吧, 这个组里面有多少条数据,取决于什么, 这个组里面,cars这个数组,group.cars, cars这个数组里面有多少条数据,是不是就是这个组里面应该显示多少条数据, return group.cars.count; 返回多少个组有了,每一组多少行也有了, 接下来,就应该返回每一组的每一行的那个单元格了吧, 首先,我们确定它返回值什么类型, - (UITableViewCell *) 然后,这个方法名叫tableView, - (UITableViewCell *)tableView, 是不是只有一个方法, //返回每一组的每一行的内容(单元格UITableViewCell) - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //所以说,在我们的UITableView里面,每一行,就一个单元格,就是UITableViewCell,但是这个UITableViewCell里面,是不是你可以放各种各样的内容啊, //我现在肯定知道两点,哪两点呢, //1.这个方法中,一定要创建一个UITableViewCell,对象, //2.这个Cell里面,是不是不是空的,一定会显示数据啊,所以说,我不管这个方法里面将来要写什么,首先我就先写这么两点, //1.获取模型数据 //因为这个Cell中,是不是一定会显示模型里面的数据, //2.创建单元格UITableViewCell //3.把模型中的数据设置给单元格中的子控件 //4.返回单元格UITableViewCell } 无论我们后三天写UITableView多么复杂,里面基本上都是这个套路,只不过是写这个具体代码时候,可能有点儿不一样,都是这四步, 我们这个groups集合中的group模型,是不是一个一个组这个模型, TestGroup *group = self.groups[section]; 但是我们具体的每一行中,是不是要显示具体的汽车品牌名称吧, 具体这个地方,要显示每一个品牌的名称 所以说,每一个UITableViewCell里面显示的品牌名称, 所以说,我们在这里,获取模型的时候, //1.获取模型数据 TestGroup *group = self.groups[indexPath.section]; //TestGroup,先获取这个组模型,indexPath,注意,indexPath这个对象里面,包含了两个信息, 这个indexPath里面,包含了两个信息: 1)一个是第几组, 2)一个是第几行, 我们首先通过它的section,拿到它是第几组, TestGroup *group = self.groups[indexPath.section]; 这样是不是获取这个组模型了, 获取组模型了以后,我们是不是要获取这一行显示什么样的品牌名称吧, 获取组模型了以后,在这个组模型里面有我们的cars,这个里面有很多很多的汽车品牌, 有很多的汽车品牌,当前到底应该显示第几个品牌,就取决于什么, 就取决于我们indexPath里面的row吧, 它里面是第几行吧,你这是第几行,我就在当前这个组里面,所有汽车品牌数组里面,找到第几个索引,把你的显示过来就OK了, 这样的话,它的返回值就是一个字符串类型, 为什么这儿返回值是一个字符串类型,因为在这个字典当中,这个数组里面返回的就是一个字符串类型, 我用字符串类型的变量接一下, //获取对应的汽车品牌 NSString *brand = group.cars[indexPath.row]; 拿到这个以后,接下来,我们在这里,要创建这个单元格了吧, 现在我是不是数据有了,所以说在这个UITableView,在这个cellForRowAtIndexPath, 在这个数据源方法中, 1)第一,获取数据, 2)第二,创建单元格, 3)第三,把数据和单元格结合, 4)第四,返回单元格, 是不是基本就这几步, 创建单元格,怎么创建, UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: nil ] ; 这样的话,我是不是创建好单元格了, 创建好单元格以后,你为单元格设置数据了吗,没有,textLabel,是不是要为这个textLabel设置数据吧, cell.textLabel.text = brand; 把这个汽车品牌设置给这个单元格中的Label, 设置好数据以后,现在单元格也有了,数据也有了,你说接下来这儿怎么写, 是不是返回单元格啊, return cell; } 这样的话,就创建好单元格了, 7.好了,我们在这个里面,就实现了: 1)动态加载这个plist,到这个数组里面,self.groups, 2)实现数据源方法,在数据源方法中,返回这个对应的数据集合中的数据, 这样是就应该有数据了吧, 但是发现什么问题,没有分组吧, 这个问题怎么解决,对,修改这个UITableView的Style属性,把它改成什么,Grouped吧, 再运行, 是不是有分组了吧,但是组标题,有吗,组描述,有吗,没有,怎么办,实现数据源方法吧, 四、设置组标题、组描述, 1.设置组标题 //设置组标题的数据源方法, - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ //这个里面这个section,是不是表示当前是第几组, //第几组的组标题,在哪里啊,对,在TestGroup里面, TestGroup *group = self.groups[section]; //self.groups,是不是根据这个section拿到第几组,然后return,这个组里面有个什么,title吧,这个就是组标题吧, return group.title; } 2.设置组描述, //设置组描述的数据源方法 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{ TestGroup *group = self.groups[section]; return group.desc; } 这样是不是就设置好组标题、组描述了,运行一下看看: 好了,这就是我们这里的加载plist文件,显示分组数据,