摘要:我仔细阅读了 Brad Larson 建议的主题 Where to place the "Core Data Stack" in a Cocoa/Cocoa Touch application,并写了一个关于如何处理模型和不同视图控制器的可能解决方案。该解决方案不使用 Core Data,但我相信相同的设计可能会应用于 Core Data 应用程序。
场景:让我们考虑一个简单的应用程序,它存储有关产品的信息,例如名称、描述和价格/单位。启动后,应用程序会显示产品列表(带有 UITableView);当用户点击产品名称时,应用程序会在另一个视图中显示产品详细信息,并使用产品名称更新导航栏。
架构这里的模型非常简单:一组 Product 对象,每个对象都有一个名称、描述和价格属性。
应用程序有三个主要视图,主要由 Xcode 的 Navigation 模板创建:一个 UINavigationView(由 UINavigationController 管理,在应用程序委托中实例化),默认 UITableView(由 RootViewController 管理,这是由UINavigationController) 和一个 DetailView(由我们必须编写的 DetailViewController 类管理)。
让我们从模型的角度来看看有什么大计划:
- 模型由 Application 委托实例化/加载为 Product 对象的 NSMutableArray;
- 模型指针现在通过属性传递给层次结构的第一个视图控制器 UITableViewController。实际上,有人可能会争辩说,层次结构中的第一个控制器是 UINavigationController,所以我们应该将引用传递给它并从它传递给 UITableViewController 但是...... Apple 说 UINavigationController 不应该被子类化,所以我们不能添加任何属性/方法。实际上这是有道理的,因为 UINavigationController 的职责始终只是可视化管理,而不是模型操作。
- 当用户选择 UITableCell 时,UITableViewController 会创建一个新的 DetailViewController(带有关联的 DetailView),将单个选定的产品作为属性传递并将 DetailView 推送到 UINavigation 堆栈的顶部。
这里有一些代码sn-ps:
模型的创建:
// SimpleModelAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// products is a protected ivar
products = [[NSMutableArray alloc] init];
Product *p1 = [[Product alloc] initWithName:@"Gold" andDescription:@"Expensive metal" andUnitPrice:100];
Product *p2 = [[Product alloc] initWithName:@"Wood" andDescription:@"Inexpensive building material" andUnitPrice:10];
[products addObject:p1];
[products addObject:p2];
[p1 release];
[p2 release];
// Passing the model reference to the first shown controller
RootViewController *a = (RootViewController*)[self.navigationController.viewControllers objectAtIndex:0];
a.products = products;
// Add the navigation controller's view to the window and display
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc
{
// The app delegate is the owner of the model so it has to release it.
[products release];
[_window release];
[_navigationController release];
[super dealloc];
}
RootViewController 可以接收模型引用,因为它有一个 NSMutableArray 属性:
// RootViewController.h
#import <UIKit/UIKit.h>
@interface RootViewController : UITableViewController
@property (nonatomic, retain) NSMutableArray *products;
@end
当用户点击产品名称时,RootViewController 会实例化一个新的 DetailViewController 并再次使用属性将单个产品的引用传递给它。
// RootViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
// Passing the model reference...
detailViewController.product = [products objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
最后,DetailViewController 会在 viewDidLoad 方法中显示设置其出口的模型信息。
// DetailViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.title = product.name;
self.descriptionLabel.text = product.description;
self.priceLabel.text = [NSString stringWithFormat:@"%.2f eur", product.unitPrice];
}
你可以在这里下载完整的项目:http://dl.dropbox.com/u/1232650/linked/*/SimpleModel.zip
我非常感谢对我的解决方案的任何评论,我渴望学习;)