【汽车品牌案例 Objective-C语言】

文章介绍了在iOS开发中如何处理plist文件数据,创建CZCar和CZGroup模型,实现字典到模型的转换,尤其是处理模型嵌套的情况。接着讲解了UITableView的数据源方法,包括分组的设置和单元格的重用,展示了如何加载数据并展示在表格视图中。
摘要由CSDN通过智能技术生成

一、刚才,我给大家说了一下这个单元格的重用,接下来,我给大家再做一个案例,

1.再做一个什么案例呢,还是显示那个汽车品牌,

汽车品牌

咱们上午是不是做过一个那个汽车品牌的展示了,做过那个展示,那是简单的一个展示,咱们再做一个,使用另外一个不同的一个plist文件,car_total.plist,使用另外一个不同的plist文件,还是展示这个汽车品牌,然后这个展示的时候,咱们就要把单元格重用给它加上了,

我们一个是再看一下,如何把这个plist文件加载起来,

另一个,还是如何利用UITableView,来展示这个数据,

然后咱们再用上那个单元格重用,

咱们把这个再给大家实现一下,

其实大家有没有发现,这个代码你敲熟以后,是不是越敲越熟,越敲越熟,

就是一开始会比较困难一些,

二、好,我们新建一个项目,汽车品牌展示02,

1.我们先把plist文件等等那些素材先拷贝进来,

在这里插入图片描述

我们上午做了这个简单这个列表吧,cars_simple.plist,

咱们现在用这个cars_total.plist,

把这个cars_total.plist拷到Supporting Files文件夹里面,

首先,我们不论干什么,首先肯定要加载这个数据吧,肯定要加载这个数据,这个数据就是,写模型,懒加载,这个是不是肯定的啊,肯定的,所以说,我们先观察一下这个plist文件结构,整体是个什么,

整体

整体是一个Array,数组吧,里面每一项又是个什么,字典,每个字典里面几个键值对,两个,一个是title,title是个A,为什么是个A,

我们看一下这个车是什么车,

这个cars里面是字符串吗,不是吧,咱们上午说的那个cars里面,这个cars数组里面就是一个一个的汽车品牌名称啊,但是这个cars里面,又是一个一个的字典吧,

这个是什么,这个字典里面包含的,一个是这个汽车品牌的图片名称,以及这个汽车的品牌吧,见过这个品牌吗,没有,这个是什么,见过这个汽车品牌吗,没有,这个见过吧,奥迪,

模型

这样的话,我们就发现,整体是一个Array数组,里面每一个元素又是个字典,这个字典里面包含一个title和一个cars,大家再观察一下,title----B、title------C、title------D,能观察出来,这个title是干什么的吗,

title

这个title就是索引,给大家演示一下这个示例程序,

示例程序

可以看到这个A、B、C、D干啥的了吗,是不是就是索引啊,就会显示到这个地方吧,

索引

显示到这个地方,

那么这个,我们可以把它做成分组的方式,我也可以给它做成不分组的方式,现在这个效果,大家告诉我,这是分组还是不分组,这个现在这个Style是Grouped的这个Style吧,咱们等会儿把它做成不是分组的Style,可以吧,

等会儿把它做成不是分组的Style,那个每一组的那个title,就是用来显示这个索引的,就是这个索引,或者这个组标题的,

ok,这就是这个title,好,然后我们继续再看,

然后,每一组里面的每一项里面的cars,就是里面有多少辆车吧,

车

注意,每一个车,包含两个信息,一个是这个车的图标,商标,一个是这个车的名称吧,

车

所以说,包含两个信息,所以说,每一个车,不是简单的一个字符串文字了,每一个车,又是一个字典,每一个车又是一个字典,

好,现在我要把这个字典懒加载,加载到程序里面,所以说,我需要先给它写模型啊,这里有几个模型,两个,

1)一个是这个模型,cars和title

模型

2)一个是里面的这个模型,icon和name,

模型

一个是汽车品牌这个模型,一个是分组这个模型,

那么这两个模型,如果是你的话,你会先写哪个,

里面这个吧,

一般的话,我们先写里面这个,因为里面这个是不是外面那个用到里面这个了,ok,所以我们先写里面这个,但是你先写外面这个也行啊,好,所以我就先写里面这个模型,里面这个就是每一辆车,每一辆车,有车的这个图片,有车的这个品牌,外面是每一组吧,是一组车啊,每一组车,这就可以看到是一组车,A,这个组车,B,这个组车,

组车

二、 这我们要写两个模型,先给模型来个前缀,CZ,

1.我们里面这个模型叫什么,是不是CZCar,汽车,

来,我们观察这个plist文件,汽车有几个属性,两个,一个是icon,一个是name,吧,

汽车

一个icon,一个name,所以里面有两个,

在CZCar.h文件里面,

#import <Foundation/Foundation.h>

@interface CZCar : NSObject

@property(nonatomic,copy)NSString *icon;

@property(nonatomic,copy)NSString *name;

@end

只有两个,所以说,我们这里有两个属性就OK了,但是写模型的时候,能写这俩吗,能是只是只写这两个吗,是不是再写一个instancetype,就OK了,

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

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

@end

这样是不是这两个初始化方法写完了,然后我们直接在这里CZCar.m文件里面,实例化一下,怎么写,

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

if(self = [super init]){

[self setValuesForKeysWithDictionary:dict];

}

return self;

}

实例化

直接setValuesForKeysWithDictionary:字典传进来,dict,

直接return,是不是就OK了,

这样的话,因为这个车,每一个车的字典,是不是就是这么一个字典,把字典传进来,是不是分别把这两个属性,赋值给对应的属性啊,

复制

好,这是这个东西,然后再写那个类方法,

+ (instancetype)carWithDict:(NSDictionary *)dict{

return [[self alloc] initWithDict:dict];

}

@end

赋值

这样的话,这个模型就写好了,

好,第一个,车模型写好了,接下来,我们是不是该写一个,就是组的一个模型了吧,

组的一个模型,CZGroup,

每一组的模型,就表示这一个item啊,

组

每一个组模型,表示一个item,

组里面,有几个属性,两个吧,一个是title,String,一个是cars,Array,

有两个,一个是String,一个是Array,

组

在CZGroup.h文件里面,

#import <Foundation/Foundation.h>

@interface CZGroup : NSObject

@property(nonatomic,copy)NSString *title;

@property(nonatomic,strong)NSArray *cars;

@end

我们看一下名称对不对,cars吧,我这里也叫cars吧,没问题,

我们也要给它封装这两个方法,那么,我要去拷贝了,

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

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

@end

来,实现一下,在CZGroup.m文件中,

#import “CZGroup.h”

@implementation CZGroup

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

if(self = [super init]){

[self setValuesForKeysWithDictionary:dict];

]

return self;

}

@end

之前是不是这么来写的:[self setValuesForKeysWithDictionary:dict];

大家看,现在这么写,有没有问题,

注意,刚才这么写没有问题,但现在这么写多少有点儿问题,

刚才,我们那个car,这个模型,里面的init方法,这么写没有问题,

模型

因为car这个字典,本身就是这么一个普通的字典,

模型

就这个字典,直接把字典里面的两个值,分别是字符串,赋值给模型里面的两个属性,就OK了,

但是,对于我们组,对于我们分组来说,这个地方就不能直接这么写了,直接这么写就有问题了,

分组

为什么啊,直接这么写的意思,是这个意思,

它会把我们这个组模型里面,

组模型

为什么啊,直接这么写的意思是这个意思,它会把我们这个组模型里面,把title直接赋值给title属性,

把cars,从plist文件读取出来以后,本身就是一个字典的数组,它会把你这个字典数组,直接赋值给cars这个数组,

数组

它会把你这个字典数组,直接赋值给cars这个数组,

但是我们要的是cars里面应该是一个包含模型的数组吧,不应该是一个字典数组吧,

所以说,这个地方,模型的嵌套,我们之前给大家讲过吧,

2.现在我们就存在一个模型的嵌套的问题了,在一个Group模型里面,又嵌套了很多的汽车模型吧,

对于这种情况,如果这个地方直接使用这种方式来赋值的话,如果直接使用这种方式来赋值的话,[self setValuesForKeysWithDictionary:dict],它相当于是这么写,

相当于这么写

self.title = dict[@“title”];

self.cars = dict[@“cars”];

看起来好像不错,第一个没有问题,但第二个有问题,因为在这个字典中,你plist文件直接读取进来以后,这个cars,它这个数组里面是一个字典数组,

它读到的这个键,cars这个键,根据这个键,取到的这个数组,也是一个什么啊,也是一个字典数组吧,也是一个字典数组,

如果你直接赋值的话,是不是把这个字典数组赋值给这个属性了,self.cars = dict[@“cars”];

但是我这里要的是什么,是一个模型数组吧,

所以说,这儿,我们要手动去改一下,当模型嵌套的时候,你不能直接使用KVC这样赋值,对于具有模型嵌套的这些地方,必须得手动把这个字典再转成模型才可以,明白,

所以说,这是模型嵌套的时候,必须注意的地方,所以说,第一个不需要改,self.title = dict[@“title”],这个不需要改,

第二个,必须要改一下,self.cars = dict[@“cars”];

怎么改呢,我们比如说是循环遍历一下吧,循环遍历一下,

需要把字典手动做一下字典转模型,

//手动做一下字典转模型,

for(NSDictionary *item_dict in dict[@“cars”]){

statements

}

//来个item_dict,

循环谁呢,字典里面,根据谁取到的,cars,先把这个根据cars取到的这个字典数组取出来,把每一个字典取出来吧,对于每个字典,我这里需要创建一个什么对象,创建一个车对象吧,要用汽车对象,所以这里要搞一个什么东西进来,把这个car模型导进来,

在CZGroup.m文件里面,

#import “CZGroup.h”

#import “CZCar.h”

@implementation CZGroup

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

if(self = [super init]){

//self.title = dict[@“title”];

//self.cars = dict[@“cars”];

[self setValueForKeysWithDictionary:dict];

//手动做一下字典转模型

for(NSDictionary *item_dict in dict[@“cars”]){

CZCar *model = [CZCar carWithDict:item_dict];

这样的话,它就把从字典中读取出来的字典数组,中的每一个字典,是不是都转成一个模型了,

转成模型以后,我们需要把它加到一个数组里面,

//创建一个用来保存模型的数组

NSMutableArray *arrayModels = [NSMutableArray array];

拿到这个

拿到这个以后,拿到我们这个空数组以后,每次创建一个模型,把它加到这个模型的数组里面,

新的这个数组里面,然后,接下来,当这个循环执行完毕以后,就把这个字典数组转成一个模型数组了,

转成模型数组以后,再手动执行一下,

self.cars = arrayModels;

这样就把这个Group里面嵌套的这个车的一个数组,转成模型数组了,

这个能看明白吗,

嵌套

这就是我们手动执行,

首先,你可以调一下这个方法,[self setValuesForKeysWithDictionary:dict];

调这个方法,就实现了,调这个方法的意思,就是上面这两句,

self.title = dict[@“title”];

self.cars = dict[@“cars”];

它直接把title属性,赋值给了self.title属性,

它直接把根据cars这个键,找到的这个字典数组,赋值给了self.cars这个属性,

但是这个时候,这个cars里面保存的是一个字典数组,

为了要把它转成模型数组,

所以说,我们手动的去创建了一个空的一个数组,

把这个字典数组中的每一个字典取出来,转成模型,

再把模型加到这个模型数组里面,

最后把这个模型数组,赋值给self.cars属性,

然后这个时候,这个self.cars属性,保存的就是模型的一个数组了,

不是字典数组了,这就是模型嵌套的时候,需要注意的这么一个问题,

当有模型嵌套的时候,需要手动把字典转成模型,

手动把字典转成模型

这样把字典转成模型了,我们Group这个模型就写完了,现在,Car这个模型也有了,Group这个模型也有了,这个两个模型类都有了,接下来,我们该去懒加载数据了吧,

三、懒加载,

1.我们看一下,这个cars_total.plist文件中分的是不是一组一组的数据啊,

一组一组的数据,

一组一组的数据

每一组里面是不是分,这个索引和这个汽车吧,

所以说,我们整体是一个组的一个数组,这里应该怎么写,是不是应该groups啊,

groups

//用来保存所有的组信息,

@property(nonatomic,strong)NSArray *groups;

//组信息是不是就在这个plist文件里面,这是一组、两组、三组、四组,

组信息

用来保存组信息的,

然后呢,每一组里面应该包含每一辆车吧,

每一辆车

接下来,我们是不是要懒加载,加载这个数据啊,

懒加载数据

懒加载数据得写谁啊,是不是getter方法吧,

#pragma mark - 懒加载数据

- (NSArray *)groups{

if(_groups = = nil ) {

NSString *path = [[NSBundle mainBundle ] pathForResource:@“cars_total.plist”];

NSArray *array = [NSArray arrayWithContentsOfFile:path ofType:nil];

NSMutableArray *arrayModels = [NSMutableArray array];

for(NSDictionary *dict in array){

CZGroup *group = [CZGroup groupWithDict:dict];

[arrayModels addObject : group ] ;

}

_groups = arrayModels;

}

return _groups;

}

把之前的代码拷过来,把对应的位置改一下,

之前的代码

把对应的位置改一下,

改一下

检查一下有没有问题,

当_groups等于空的时候,把这个cars_total.plist加载进来,初始化完整路径,然后加载进来,然后遍历一下这个字典数组,把里面的每一个字典,转成模型,里面的小字典,cars,也在同时转成模型,然后把这个大字典转成的模型,加到可变数组里面,然后把这个可变数组赋值给这个_groups属性,最后,把_groups属性返回,

这样是不是就完成我们的懒加载了,

当懒加载完毕以后,我们是不是就该拖一个UITableView,展示数据了,我们就拖一个UITableView,

二、拖一个UITableView,

1.把控制器管理的View,改成3.5英寸,把模拟器改成iPhone4S,

我们拽一个UITableView,填满整个屏幕,

现在UITableView有了,要想让它显示数据,首先得怎么办,设置数据源对象吧,

2.设置数据源对象,两种方法,

1)拖线

2)viewDidLoad里面,self.tableView.dataSource = self;

我们使用拖线的方式,

设置数据源对象

控制器是不是成为它的数据源了,

控制器成为它的数据源以后,要怎么样,遵守那个协议,遵守数据源协议吧,

遵守数据源协议

@interface ViewController () < UITableViewDataSource >

3.然后,遵守数据源协议以后,要实现一些什么,三个数据源方法吧,

1)有多少个组,numberOfSectionsInTableView,

2)每一组有多少个行,numberOfRowsInSection,

3)每一组每一行返回什么样儿的单元格,cellForRowAtIndexPath,

#pragma mark - 数据源方法

//1.因为,我们这里是单组数据,所以,第一个数据源方法可以不实现,

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

return 1;

}

//如果要是多组数据的话,这个方法就得实现一下了,

//2.第二个数据源方法,返回每一组有多少个行吧,这个方法的返回值类型是什么,NSInteger吧,

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

//因为,就一组,所以说,所有的数据是不是都在这一组里面,所以说,groups,下面有多少条记录,表示这一组里面,有多少条记录啊,

return self.groups.count;

}

//就这么一个,这样的话,就有这么多个组,有这么多个组,

//然后,接下来,先让我们看一下怎么处理啊,然后,现在我们需要实现的是,每一组返回什么样的单元格吧,每一组返回什么样的单元格,

//3.每一组返回什么样的单元格,返回单元格是什么类型,UITableViewCell,

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

//在这个里面,我们要返回对应的数据了吧,

}

返回单元格

我们先看一下这个示例程序,

示例程序

在这个示例程序里面,每一行是不是都是显示的具体的车这个数据,

组数据看到了吗,

组数据,就是个框架,里面就是包含了个索引而已啊,里面就显示,就是我们这个一辆一辆的车吧,里面就是一辆一辆的车,所以说,我们这个地方,是要把这个一个一个车给它显示出来,

好,我们这里把这个车,把它显示出来,

我们这里,不论将来显示什么样的车,不论这个UITableViewCell里面将来显示什么样的数据,反正它肯定是

1)第一:获取模型数据,

2)第二,返回对应的创建单元格吧,

3)第三,设置单元格的内容,

4)第四,返回单元格,

3.每一行显示什么样的单元格的数据源方法,

1)第一,获取模型数据,

//1.获取模型数据,

//我们先看看,单行数据能不能展示出来,

组信息

//这个是我们一个一个的组信息,

//你要根据第几组……

//咱们这儿还是用分组展示合适,还是用分组展示合适,单组好像不太合适,因为什么呢,因为注意看这里,因为我们整个儿这个Array里面,包含的是一组一组的信息,它不是那个,不是我们一行一行的信息,它包含的是一组一组的信息,所以说这儿,咱们这儿有点问题,注意看,

//这儿,不应该返回几组,不应该返回1组,

不应该返回1组

//这儿不应该返回1组,因为我们整体这个plist文件,包含的是一组一组的信息,就是说,这个plist文件里面有多少个Dictionary,就表示有多少个组,

组

//这个地方不应该返回1组信息,应该返回self.groups.count;

组

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

return self.groups.count;

}

self.groups.count,这是表示有多少个组吧,这儿应该返回多少组,这儿不应该返回一组,这儿应该返回有多少组,

因为现在plist文件中,每一个项,它就是表示一组,它不是表示一条数据,明白,它就表示一组,所以说,这个地方不应该返回一组,

然后,这个地方,每一组返回多少行,

每一组返回多少行

这儿是不是要根据组来决定啊,这个是每一组返回多少行啊,注意,

那么,你要返回每一组有多少个行,是不是得先拿到每一组的组对象吧,

组对象

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

CZGroup *group = self.groups[section];

//根据当前组索引,这个section,根据这个组索引,就拿到当前组这个对象了,

//然后,这个组里面有多少条记录,怎么写,

return group.cars.count;

//然后,当前这个组里面,有一个属性,叫做cars,这个数组啊,然后它点count,这个才表示每一组有多少辆车啊,这个是返回每一组有多少行,

//这个是返回每一组有多少辆车,

//刚才咱们不应该返回1组,应该是有多少个组,就返回多少个组,

//然后呢,这个地方是每一组多少辆车,返回组里面的cars,应该这么来写,

}

然后,下面才是获取模型,创建单元格,设置单元格,返回单元格,

创建

因为最终,我在这个示例程序里面,每一行,需要显示车的信息,

所以说,你在获取模型的时候,不仅要获取组模型,是不是还得获取车模型啊,ok,首先,获取组模型,

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

//1.获取组模型和车模型,

//首先,获取组模型,self.groups,这个地方,根据indexPath.section,根据section获取组模型,

CZGroup *group = self.groups[indexPath.section];

//然后,获取车模型,

//这个地方,没有导入CZCar.h文件,所以,需要先导入CZCar.h文件,#import “CZCar.h”,

//我们这个地方,只导入了CZGroup.h头文件吧,Group里面有Car吗,没有,在.m文件里面,所以我们这个地方还得导入,

//等于当前这个group的cars数组里面,你当前循环的是第几行,我就把第几辆车的信息取出来,

CZCar *car = group.cars[indexPath.row];

}

组索引

//根据组的索引获取对应的组的模型

CZGroup *group = self.groups[indexPath.section];

//根据当前行的索引,获取对应组的对应行的车,

CZCar *car = group.cars[indexPath.row];

然后,拿到这个数据模型以后,接下来,是不是要创建单元格了,创建单元格,我们说,现在要进行单元格的重用,所以说,能直接就是alloc init 吗,不合适吧,这儿应该怎么样,

//2.创建单元格

//2.1 声明一个重用ID

static NSString *ID = @“car_cell”;

//2.2 根据重用ID去缓存池中获取对应的cell对象

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

//这样就拿到我们的这个根据重用ID,去找到这个cell了,

//然后,是不是有可能找到,有可能找不到啊,

//2.3 如果没有获取到,那么就创建一个,怎么创建,

if(!cell){

//就开始创建就可以了,注意,我们这里用Default这个样式就可以了,

//然后,创建单元格的时候,指定一个什么,指定一个重用ID,

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];

}

这样的话,是不是就实现了,我们创建单元格的时候,先从缓存池里面取,取不到以后,你再创建啊,

创建好以后,接下来,我们要做的是什么,把这个数据设置给这个单元格吧,

//3.把数据设置给单元格,

cell.imageView.image = [UIImage imageNamed:car.icon];

//等于什么,car这个模型的icon吧,是不是就把这个icon赋值给这个image了,

//然后,接下来,再设置它的品牌名称,

cell.textLabel.text = car.name;

//是不是品牌,好,现在数据模型取出来了,单元格创建好了,数据设置好了,

在这里插入图片描述

数据

//接下来,该干什么了,是不是返回单元格啊,

//4.返回单元格,

return cell;

}

运行一下看看,

运行

看到这个数据了吗,看到了吧,但是是分组了吗,没有吧,为什么没有分组,对,需要先把它的样式改一下吧,

样式

先选中这个tableView,改它的Style,是什么Style,Grouped吧,

这样是不是显示出来了,对,没有图片吧,

图片

我们看一下为什么没有图片,难道是这个Default样式不行吗,Default不行,就给它改成Subtitle,

样式

还是没有图片,

这样的话,是不是就是有可能是我这个icon这儿有问题啊,有可能是这个icon这儿有问题,我们看看是不是没拷素材,

没拷素材

哦,没拷素材吧,没拷素材,

所以,图片没显示,就是icon这儿有问题,或者是没拷素材,把素材拷进来,

素材

再运行开一下,

图片

这样就都有了吧,这样就都有了,

这样的话,分组也有了,然后数据也显示出来了,但是我们看,我们说每一项这儿是不是要显示每一个组对应的那个索引吧,是不是那个A、B、C、D……Z,要显示那个组的索引吧,

怎么设置每一组的组标题,是不是有个数据源方法叫做ForHeaderTitle、ForHeaderView那个东西吧,

在这里插入图片描述

四、设置每一组的组标题,

1.这个数据源方法,返回组的标题,它的返回值类型是什么类型,NSString吧,

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{

//这儿是不是也要获取那个组模型,也要获取组模型,

CZGroup *group = self.groups[section];

//获取组模型以后,把组模型里面的什么,group.title,这是不是就是那个对应的组的那个A、B、C、D的索引吧,

return group.title;

}

然后,再运行一下看看,

运行

这个时候,是不是就有这个A、B、C、D这个东西了吧,

你如果不希望是这个分组的这个效果的话,这个时候可以怎么办,可以设置完组标题以后,再把这个样式改回来,改成Plain,

Plain

改成Plain,把样式,

然后你再运行的时候,

运行

这个东西就给它顶起来了,

就是类似这个效果,我把状态栏给它去掉了,

prefersStatusBarHidden,

- (BOOL)prefersStatusBarHidden{

return YES;

}

好,这就是我们这个汽车品牌案例,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清风清晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值