UITableView

UITableView继承于UIScrollView,可以滚动。 UITableView的每一条数据对应的单元格叫做Cell,是UITableViewCell一个对象,继承于UIView。 UITableView可以分区显⽰示, 每一个分区称为section, 每一⾏称为row, 编号都从0开始。 系统提供了一个专门的类来整合section和row,叫做NSIndexPath。

//创建UITableView

   UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.boundsstyle:UITableViewStylePlain];    

[self.view addSubview:tableView];    

[tableView release];

//UITableView的样式枚举

  // UITableView的初始化⽅方法包含⼀一个UITableViewStyle类型的参数 这是⼀一个枚举类型    

typedef NS_ENUM(NSInteger, UITableViewStyle) 

{        UITableViewStylePlain,        UITableViewStyleGrouped    };

//UITableView的相关属性

   //rowHeight        行高

   //separtorStyle    分隔线样式

   //separtorColor    分隔线颜⾊

   //tableHeaderView  UITableView的置顶视图

   //tableFooterView  UITableView的置底视图

//UITableView中有两个重要的属性:

   @property (nonatomic, weak, nullable) id     dataSource;

    //dataSource 显示数据相关的代理    @property (nonatomic, weak, nullable) id     delegate;

    //delegate   视图操作相关的代理


//UITableView代理的实现代码

   1.签订UITableView协议    

   2.设置当前的ViewController为 UITableView

//UITableViewCell

   //UITableView的每一个单元格是UITableViewCell类的对 UITableViewCell默认提供了3个视图属性:

   UIImageView *imageView  图片视图

   UILabel *textLabel      标题视图

   UILabel *detailTextLabel 副标题视图

//UITableView重用cell的代码流程

   1. 在创建UITableView之后,需要注册一个cell类,当重用池中没有 cell的时候,系统可以自动创建cell。 相关方法:    - (void)registerClass:(Class)cellClass forCellReuseIdentifier: (NSString *)identifier;    2.系统提供了一个获取重⽤用池中cell的⽅方法(需要提供一个重用标 识):    - (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;

//UITableViewController

   UITableViewController是继承于UITableViewController中的一个 类,只不过⽐比UITableViewController中多了一个属性tableView。 即:UITableViewController是一个自带table的视图控制器。

 一:UITableViewController继承自UITableViewController,自带 一个ableVie   

 二:[self.view]不是UIView而是UITableView   

 三:datasource和delegate默认都是 self(UITableViewController)    

 四:开发中只需要建立UITableViewController子类

UITableView   需要签订两个协议,一个是datasource,一个是delegate

dataSource:

UITableViewDataSource类型

主要为UITableView提供显示用的数据(UITableViewCell),指定UITableViewCell支持的编辑操作类型(insert,delete和reordering),并根据用户的操作进行相应的数据更新操作,如果数据没有更具操作进行正确的更新,可能会导致显示异常,甚至crush。

//调用数据源的下面方法得知一共有多少组数据

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

//调用数据源的下面方法得知每一组有多少行数据

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

//调用数据源的下面方法得知每一行显示什么内容

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

delegate:

UITableViewDelegate类型,主要提供一些可选的方法,用来控制tableView的选择、指定section的头和尾的显示以及协助完成cell的删除和排序等功能。

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;

这里注意:如果不是cell有不同高度的需求,在设置cell的高度上,最好不要用这个,直接在创建tableview的时候,设置rowHeight即可。

accessoryType属性:

辅助指示视图的作用是显示一个表示动作的图标,可以通过设置UITableViewCell的accessoryType(其属性)来显示,默认是UITableViewCellAccessoryNone(不显示辅助指示视图),其他值如下:

UITableViewCellAccessoryDisclosureIndicator       箭头

UITableViewCellAccessoryDetailDisclosureButton 按钮+箭头

UITableViewCellAccessoryCheckmark                       对勾

UITableViewCellAccessoryNone                                       没有

UITableViewCellAccessoryDetaiButton                          叹号按钮

UITableViewCellStyle四种样式

UITableView_第1张图片

cell的重用原理

iOS设备的内存有限,如果用UITableView显示成千上万条数据,就需要成千上万个UITableViewCell对象的话,那将会耗尽iOS设备的内存。要解决该问题,需要重用UITableViewCell对象

原理:

当滑动列表时,部分cell会移处窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,等待重用。当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,如果池中有未使用的UITableViewCell,dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象

注意:

有时候需要自定义UITableViewCell,而且每一行用的不一定是同一种cell,所以一个UITableView可能拥有不同类型的UITableViewCell。对象池中也会有很多不同类型的UITableViewCell,那么在UITableView重用cell时可能会得到错误类型的UITableViewCell

解决方案:

UITableViewCell有个NSString *reuseIdentifier属性,可以在初始化UITableViewCell的时候传入一个特定的字符串标识来设置reuseIdentifier(一般用UITableViewCell的类名)。当UITableView要求dataSource返回UITableViewCell时,先通过一个字符串标识到对象池中查找对应类型的UITableViewCell对象,如果有,就重用,如果没有,就传入这个字符串标识来初始化一个UITableViewCell对象

cell的重用代码

方法一:

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

{//注意:重用机制是根据相同的标识符来重用cell,标识符不同的cell不能彼此重用

  1.定义一个cell的标识为ID

     staticNSString*ID =@"mjcell";

  2.从缓存池中取出cell

     UITableViewCell*cell = [tableView  dequeueReusableCellWithIdentifier:ID];

3.如果缓存池中没有cell

     if(cell ==nil) {

        cell = [[UITableViewCellalloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];

    }

 4.设置cell的属性...

 return cell;

}

方法2:注册

[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]

拓展一:UITableView的cell侧滑删除按钮

//1.该行能不能编辑

-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPaht *)indexPath{

return YES;

}

//2.提交编辑

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{

//以下语句不能调换顺序,不然删除会崩溃报错

//1.删除对应数据源中的方法

[self.data removeObjectAtIndex:indexPath.row];

//2.删除界面上的哪一行

[tableView deleteRowsAtIndexPath:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

}

//3.设置删除按钮的文字(默认是英文的delete)

-(NSString *)tableView:(UITableView *)tableView  titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{

return @"删除";

}

拓展二:UITableView 的cell增加

先创建一个按钮,在按钮点击事件里设置进入编辑状态

[self.tableView setEditing:YES];

UITableView_第2张图片

点击增加按钮,cell进入编辑状态,默认还是删除。想变成增加,需下面这个方法

//增加cell

-(UITableViewCellEditingStyle)tableview:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{

//默认情况下是删除

return UITableViewCellEditingStyleInsert;

}

这个时候,-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath这个方法就需要做出判断,如果是删除style执行删除cell,如果是增加style那就执行增加

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{

if(editingStyle == UITableViewCellEditingStyleDelete){

//以下语句不能调换顺序,不然删除会崩溃报错

//1.删除对应数据源中的方法

[self.data removeObjectAtIndex:indexPath.row];

//2.删除界面上的哪一行

[tableView deleteRowsAtIndexPath:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

}

}else if(editingStyle == UITableViewCellEditingStyleInsert){

//增加数据源

[self.data insertObject:@"新数据" atIndex:indexPath.row];

//刷新整个表格

//[self.tableView reloadData];(这里需要注意,如果想刷新tableview,用这个方法是没问题,但是这个是刷新整个表格,如果只是单纯增加或删除一行cell,没必要刷新整个表格,来耗内存)

[tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];

}

UITableView_第3张图片

拓展三: UITableView 的cell移动

先创建一个按钮,在按钮点击事件里设置进入编辑状态

[self.tableView setEditing:YES];

进入编辑状态后,tableviewcell的右边会出现一个图标,进行拖拽到你想移动的cell位置

//移动cell

-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath{

return YES;

}

-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{

//1.移除需要移动的cell

NSString *cellData = self.Data[sourceIndexPath.row];

//2.移除原始位置的数据

[self.data removeObjectAtIndex:sourceIndexPath.row];

//3.往目标位置插入一个数据

[self.data insertObject:cellData atIndex:destinationIndexPath.row];

(注意:如果没有以上这三点,只有两个移动cell函数的话,移动后的cell,在你滑动tableview的时候,数据还会变成原本数据,需要你对移动的数据进行重新处理)

}

最后,编辑完成,根据项目需求,在你点击完成的事件函数里,设置[self.tableView setEditing:NO];

为什么很多内置类如UITableViewController的delegate属性都是assign而不是retain呢?

会引起循环引用----若是retain,在alloc一次之后,若release一次,会导致内训泄漏,若release两次会导致两个 对象的dealloc嵌套执行,结果就是都没有执行成功,最后崩溃! 所有的引用计数系统,都存在循环应用的问题。例如下面的引用关系:

* 对象a创建并引用到了对象b. * 对象b创建并引用到了对象c. * 对象c创建并引用到了对象b.

这时候b和c的引用计数分别是2和1。 当a不再使用b,调用release释放对b的所有权,因为c还引用了b,所以b的引用计数为1,b不会被释放。 b不释放,c的引用计数就是1,c也不会被释放。从此,b和c永远留在内存中。 这种情况,必须打断循环引用,通过其他规则来维护引用关系。我们常见的delegate往往是assign方式的属性而不是 retain方式 的属性,赋值不会增加引用计数,就是为了防止delegation两端产生不必要的循环引用。 如果一个UITableViewController 对象a通过retain获取了UITableView对象b的所有权,这个UITableView对象b的 delegate又是a,如果这个delegate是retain方式的,那基本上就没有机会释放这两个对象了。自己在设计使用 delegate模式时,也要注意这点。

你可能感兴趣的:(UITableView)