我是iOS应用程序开发的新手,但我正在努力学习如何以最佳方式处理Cocoa。
我试图理解如何正确保存和引用模型对象。
你能给我一些提示(和代码示例)吗?我想以适当的方式学习这些东西,考虑到我将很快转向核心数据。
答案 0 :(得分:12)
摘要:我仔细阅读了Brad Larson建议的主题Where to place the "Core Data Stack" in a Cocoa/Cocoa Touch application,并写了一个关于如何处理模型和不同视图控制器的可能解决方案。该解决方案不使用Core Data,但我相信相同的设计可能会应用于Core Data应用程序。
场景:让我们考虑一个简单的应用程序,它存储有关产品的信息,例如名称,描述和价格/单位。启动后,应用程序会显示一个产品列表(带有UITableView);当用户点击产品名称时,应用程序会在另一个视图中显示产品详细信息,并使用产品名称更新导航栏。
架构这里的模型非常简单:一个Product对象数组,每个对象都有一个名称,描述和价格属性。
该应用程序有三个主要视图,主要由Xcode的导航模板创建:UINavigationView(由UINavigationController管理,在app委托中实例化),默认的UITableView(由RootViewController管理,是第一个由UINavigationController)和DetailView(由我们必须编写的DetailViewController类管理)。
让我们从模型的角度看看大计划是什么:
这里有一些代码片段:
创建模型:
// 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/stackoverflow/SimpleModel.zip
我真的很感激对我的解决方案的任何评论,我渴望学习;)
答案 1 :(得分:1)
更有经验的同事建议在AppDelegate中拥有相关属性。 IMO最好在特定控制器中使用特定的模型集。
答案 2 :(得分:0)
我也是个菜鸟,但这就是我的所作所为。它最像#2。
在applicationDidFinishLaunching中,app delegate创建模型的实例。
我的视图控制器声明了一个指向模型的属性,但类型是一个协议(在我的例子中是id <GameModel>
。协议中的许多属性都被声明为readonly。
在applicationDidFinishLaunching中,app委托将属性设置为指向它创建的模型。
我不喜欢的事情:
一。您的视图控制器不应该知道您的应用程序委托的结构。您可以在另一个应用程序中重用相同的视图控制器,并使用不同的应用程序委托类型。您可以对视图控制器代码进行简单的更改以解决这个问题,或者还有其他方法可以解决这个问题,但为什么要这么做呢?
三。我不像大多数人那样喜欢单身人士。问题是他们是单身。如果您想加载多个模型怎么办?
四个。 ?!?!