好的,我理解你的沮丧,因为绝大多数 iPhone 教学材料都没有对整体应用程序设计给予足够的关注。他们为眼睛糖果界面做了一条直线,并且只口头上说应用程序应该处理数据,即使处理数据首先是应用程序的全部目的!
指导材料没有花足够的时间来解释整个 iPhone/Cocoa API 所基于的模型-视图-控制器设计模式。你很难理解任何事情,因为你一直试图将功能塞进错误的对象中,错误地认为 UI 视图是程序的核心,因为教学材料让你相信。在这种误解下,没有任何意义,即使是 Apple 文档。
你需要退后一步重新思考。决定显示什么数据以及何时显示它不是视图的功能。保存、管理或存储应用程序的数据不是表格视图控制器的功能。这些函数正确地属于数据模型对象(您可能从未听说过。)您遇到了麻烦,因为您试图在视图和视图控制器之间拆分数据模型任务,如果它们不属于它们。
显然,您的应用程序甚至没有数据模型,因为您将表的数据作为 tableview 控制器的属性保存。尽管您经常在简单的教程示例中看到这一点,但这是一个糟糕的设计,它会在除最微不足道的应用程序之外的任何应用程序的复杂性下崩溃。
相反,您的数据应该在其自己的自定义对象中存储和管理。这是数据模型。在您的情况下,听起来您的数据分布在两个数组中,因此您将创建一个数据模型对象,如下所示:
@interface MyDataModel : NSObject {
@protected
NSArray *arrayOne;
NSArray *arrayTwo;
@public
NSArray *currentlyUsedArray;
}
@property(nonatomic, retain) NSArray *currentlyUsedArray;
-(void) switchToArrayOne;
-(void) switchToArrayTwo;
-(void) toggleUsedArray;
@end
#import "MyDataModel.h"
@interface MyDataModel ()
@property(nonatomic, retain) NSArray *arrayOne;
@property(nonatomic, retain) NSArray *arrayTwo;
@end
@implementation MyDataModel
- (id) init{
if (self=[super init]) {
self.arrayOne=//... initialize array from some source
self.arrayTwo=//... initialize array from some source
self.currentlyUsedArray=self.arrayOne; //whatever default you want
}
return self;
}
-(void) switchToArrayOne{
self.currentlyUsedArray=self.arrayOne;
}
-(void) switchToArrayTwo{
self.currentlyUsedArray=self.arrayTwo;
}
- (void) toggleUsedArray{
if (self.currentlyUsedArray==self.arrayOne) {
self.currentlyUsedArray=self.arrayTwo;
}else {
self.currentlyUsedArray=self.arrayOne;
}
}
(注意实际数据是封装的,其他对象只能访问currentlyUsedArray
。数据模型根据数据的内部状态决定提供哪些数据。)
此数据模型对象应位于普遍可访问的位置。最好的方法是让它成为一个单例,但快速而肮脏的方法是将它作为应用程序委托的属性停放。
因此,在您的 tableview 控制器中,您将拥有一个属性:
MyDataModel *theDataModel;
@property (nonatomic, retain) MyDataModel *theDataModel;
然后在实现中
@synthesize theDataModel;
-(MyDataModel *) theDataModel; {
if (theDataModel; !=nil) {
return theDataModel; ;
}
id appDelegate=[[UIApplication sharedApplication] delegate];
self.theDataModel=appDelegate.theDataModelProperty;
return theDataModel;
}
然后在您的 tableview 数据源方法中:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
...
cell.textLabel.text=[self.theDataModel.currentlyUsedArray objectAtIndex:indexPath.row];
return cell;
}
如果应用程序中的某个事件需要您切换数组,您只需从应用程序委托调用数据模型对象并向其发送适当的切换数组消息。
id appDelegate=[[UIApplication sharedApplication] delegate];
[appDelegate.theDataModelProperty toggleUsedArray];
现在所有后续的数据操作,无论是在那个特定的表视图中还是在其他一些完全不相关的视图中,都将使用正确数组中的数据。
为什么要经历所有这些麻烦?它使应用程序模块化。您可以轻松添加不同的视图,每个视图都以不同的方式显示数据,而无需每次都重写数据管理。您可以使用数据模型来管理将在表格、Web 视图或命令行中显示的数据。您甚至可以轻松地将数据模型移动到完全不同的应用程序中。
这种模块化使大型复杂应用程序的管理变得更加容易。您只有一个操作和控制数据的对象。您不必担心一些很少使用的代码段中的一些小错误会破坏整个应用程序。您可以轻松插入视图或轻松删除它们,而不会破坏应用程序。
这当然是一个微不足道的例子,但它显示了良好的实践。
但是,你可能会问,这如何解决 tableview 知道要加载哪些数据以及何时加载的问题?很简单,它没有。知道要加载什么数据或何时加载不是 tableview 的工作。数据模型处理what-data,tableview控制器处理when。(您甚至可以在更新数据模型时发出通知,例如针对 url。然后视图控制器可以注册通知并reloadData
在数据模型更改时调用。)
通过在 MVC 中无情地划分和封装功能,您可以从易于维护和调试的简单、可重用的组件创建复杂的应用程序。
真的很糟糕,大多数教学材料只对这个完全关键的概念作了口头上的服务。