接触了两天的UITableView,由于目前我们编程采用的是MRC管理内存模式,所以最近各种内存问题随之出现了,各种滑动TableView随后进行一系列的操作(譬如删除Cell,增加Cell等等),然后程序崩溃。
常见的崩溃现象有下面几种:
1.刚要滑动UITableView程序立刻崩溃,这种情况通常是获许数据时,定义了相关的属性(数组,字典),通常定义完属性之后,我们立刻会重写dealloc方法。此时,如果我们在下面采用便利构造器进行数组或者是字典的初始化的时候,采用带下划线变量名的方式,程序必崩无疑,此时我们需要采用点语法调用setter使其引用计数加1,进行数据的持有。
2.UITableView中的dataSource中必须要实现的两种方法必须要实现。
3.还有一些常见的崩溃问题在对Cell进行操作的基础上,程序中的代码理解不到位,导致的程序崩溃。最常见的就是删除Cell时,对数组和字典的操作,问题的关键是要将数据源与Cell对应起来。
上面是我在学习UITableView遇到的一些问题,既然是对UITableView做一个简单地小结,还是将它的简单地用法说明一下吧!
UITableView *tableView = [[UITableView alloc]initWithFrame:[[UIScreen mainScreen]bounds] style:UITableViewStylePlain];
tableView.delegate = self;
tableView.dataSource = self;
[self.view addSubview:tableView];
[tableView release];
上面这段代码是一个UITableView必须要写的步骤,还有一些属性,你可以根据你的需求进行添加。例如rowHeight是设置每一行的高度,当然你也可以用代理中的方法对每一行设置不相同的高度;cell.imageView.image是在添加一个图片;cell.accessoryType设置辅助视图;cell.detailTextLabel.text相当于副标题的作用等等。
dataSource中必须要实现的两个方法:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
特定分区的行数
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
给每一行提供数据,一共有多少行就执行多少次 这段代码中indexPath的两个属性section和row自己会进行自增。
这里说明一下UItableViewCell采用的重用机制,来减少Cell的创建,采用MutableSet来管理Cell,具体思路如下:
1.先判断重用池里面是否有cell,如果有cell直接从重用池里面取出Cell
2.如果没有Cell创建Cell对象
3.配置Cell上面现实的数据
还有一个可以选择实现的方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// 返回tableView一共多少个分区。
return 3;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 点击Cell后跳转界面或者是其他操作必须要实现的方法
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 ) {
return 50;
}
else{
return 100;
}
// 设置每一个分区的行高
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
NSArray *aa = @[@"A",@"B",@"C",@"23455",@"1234"];
return aa;
// 右侧快速索引(可以快速定位到相应的分区)
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
// 给想要的分区起个名字。
}
下面说明的一下方法是对UITableView进行编辑要实现的方法:
1.删除Cell或者添加Cell要实现的几个步骤:
#warning 1-1让tableView处于编辑状态
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
// 点击EditButtonItem 的时候,会调用的方法。
// EditButtonItem 按钮再点击的过程中慧自动改变Editing的状态,Edit对应yes, done 对应no 这之间的切换在系统自己内部已经实现,我们只需要调用[super setEditing:editing animated:animated];就行
}
#warning 1-2设置哪些行可以编辑,默认情况下所有行都可以编辑
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
#warning 1-3 设置可编辑行的编辑状态。默认的编辑状态时删除
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
// return UITableViewCellEditingStyleInsert | UITableViewCellEditingStyleDelete;
return UITableViewCellEditingStyleDelete;
}
#warning 1-4 完成编辑后需要完成什么事情。例如:点击删除按钮,删除相应的行,点击添加按钮,添加一行数据
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete){
// 在进行删除的时候,应该先删除数据源,然后再删除对应的行。原因是做操作的时候,会自动调用numberOfRowsInSection方法,如果先删除行,其数据源和行数还是对应不起来,多以应该先对数据源进行操作,在对行进行操作。
#pragma 方法一
[_array removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
#pragma 方法二
// [tableView beginUpdates];
// // 无关循序的执行
// [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
// [_array removeObjectAtIndex:indexPath.row];
// [tableView endUpdates];
#pragma 方法三
// [_array removeObjectAtIndex:indexPath.row];
// [tableView reloadData];
#pragma 方法四
// [_array removeObjectAtIndex:indexPath.row];
// NSIndexSet *accc = [NSIndexSet indexSetWithIndex:0];
// [tableView reloadSections:accc withRowAnimation: UITableViewRowAnimationFade];
}
}
2.对UITableView中的Cell进行移动
#warning 2-1让tableView处于编辑状态
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
// 实现tableView的编辑状态
// 点击EditButtonItem 的时候,会调用的方法。
// EditButtonItem 按钮再点击的过程中慧自动改变Editing的状态,Edit对应yes, done 对应no 这之间的切换在系统自己内部已经实现,我们只需要调用[super setEditing:editing animated:animated];就行
}
#warning 2-2设置那些行可以移动。默认是不可以移动的
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
#warning 2-3 从某一行移动到另外一行时需要做什么事情
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
NSLog(@"%@,%@",sourceIndexPath,destinationIndexPath);
// 调用retain防止野指
NSString *str = [_array[sourceIndexPath.row]retain];
[self.array removeObject:str];
[self.array insertObject:str atIndex:destinationIndexPath.row];
[str release];
}
#warning 2-4 限定划分区域移动
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
/*
if (sourceIndexPath.section == proposedDestinationIndexPath.section) {
return proposedDestinationIndexPath;
}else{
return sourceIndexPath;
} // 这段代码表示不能跨区域移动
*/
if (sourceIndexPath.section == proposedDestinationIndexPath.section) {
return proposedDestinationIndexPath;
}else{
return proposedDestinationIndexPath;
} // 这段代码表示能跨区域移动
}
通常UITableView与容器控制器还有轮播图配合使用,所以UITableView必须要重点掌握!