如何从UITableView中删除一行?
在创建Simple Table 应用程序时,经常有人提到上述问题,
在开始编码之前,我先介绍下 Model-View-Controller 模式,这个模式是在用户界面编程中经常引用的设计模式之一。
1.理解 Model-View-Controller
不管学习什么语言,成为一个更好的开发人员所需要了解的概念是Separation of Concerns (SoC , 关注点分离).
这个概念很简单,关注点是软件功能的不同方面,这个概念是鼓励开发人员将一个大的功能或程序分为几个关注点区域,每个区域都有自己的职责。在iOS编程中经常发现的委托模式(delegate pattern),也是SoC模式的一个例子。
这里的MVC模式是另一个SoC的范例。MVC的核心思想是分离用户界面为3个区域,每一个区域负责特定的功能。如果MVC名字上暗示了一样,MVC将用户界面分为3个部分:
Model - 模型负责保存数据和数据上的操作。模型可以很简单,如一个数组对象存放所有的表数据。新增、编辑和更新是数据操作方法。实际上,操作方法经常认为是业务逻辑(Businsess Rules).
View - 视图管理信息的可视化显示,例如,UITableView 以表示图格式显示信息
Controller - 控制器是Model 和 View 之间的桥梁,负责转换视图中用户交互(如轻拍操作)为执行模型中的合适方法。例如,用户轻拍了视图中的一个删除按钮,相应的,控制器出发模型中删除操作方法。随后,在要求视图更新自己,并反应出数据模型的更新。
2.如何从UITableView 中删除行数据
我们有3项工作要做:
1)编写代码,切换到编辑模式,实现行删除
2)从模型中删除相应的表数据项
3)再次加载表视图,以便反映出表数据的变化
1)编写代码,切换到编辑模式,实现行删除
在iOS App中,用户通过划过一行,初始化删除按钮。回想一下,我们使用了UITableViewDataSource协议,可参考API文档,其中有一个方法:
tableView:commitEditStyle:forRowAtIndexPath.当用户划过一行时,表视图将检查该方法释放实现。如果发现该方法,表视图将自动显示删除按钮。
即便该方法是空的,并没有执行任何操作,当你划过一行时,仍然可以看到删除按钮。
2)从模型中删除相应的表数据项
接下来的工作是添加代码到该方法中,删除实际的表数据。和其它表视图方法一样,它传入indexPath 参数,告诉你需要删除的行号(row number),因此,你可以使用这一信息,从表数组中删除对应的元素。
在Simple Table 应用程序中,我们使用NSArray 数组来存放表数据(也就是模型)。问题是NSArray 是不可编辑的,也就是在数组初始化之后,你无法添加、删除其内容。可选办法是,我们将使用NSMutableArray 代替 NSArray,
NSMutableArray 提供了新增和删除操作方法:
@implementation SimpleTableViewController
{
NSMutableArray *tableData;
}
在tableView:commitEditStyle方法中,添加如下代码,从数据中删除实际的数据。代码如下:
- ( void )tableView:( UITableView *)tableView commitEditingStyle:( UITableViewCellEditingStyle )editingStyle forRowAtIndexPath:( NSIndexPath *)indexPath
{
//Remove the row from data model
[ tableData removeObjectAtIndex :indexPath. row ];
}
NSMutableArray 提供了一些方法用来操作数组的内容。这里,我们使用removeObjectAtIndex 方法从数组中删除特定项,并删除一行。悲催,App并没有按预期工作。
这并不是bug。App确实从数组中删除了该数据项。已删除的数据项仍然出现在视图中的原因是视图没有刷新,无法反应出数据模型的更新。
3)再次加载表视图,以便反映出表数据的变化
因此,一旦底层的数据删除了,我们需要调用reloadData方法,要求表视图刷新,如下是更新之后的代码:
- ( void )tableView:( UITableView *)tableView commitEditingStyle:( UITableViewCellEditingStyle )editingStyle forRowAtIndexPath:( NSIndexPath *)indexPath
{
//Remove the row from data model
[ tableData removeObjectAtIndex :indexPath. row ];
//Request table view to reload
[tableView reloadData ];
}