如何处理 iOS 应用程序中的模型类

Posted

技术标签:

【中文标题】如何处理 iOS 应用程序中的模型类【英文标题】:How to deal with model classes in iOS application 【发布时间】:2011-11-03 00:01:51 【问题描述】:

我是 ios 应用程序开发的新手,但我正在努力学习如何以最佳方式处理 Cocoa。

我在试图了解如何正确保存和引用模型对象时陷入困境。

    很多人说要编写一个应用委托属性来保存模型,然后通过应用委托单例的便捷方法来引用它。 其他人说只在视图控制器中“注入”它需要(或其子视图需要)的模型部分,但我不明白如何做到这一点。通过财产?通过 initWithModel: 方法(在这种情况下,我如何让 IB 使用该方法?) 其他人又说模型应该是单例的 还有人说要使用全局变量 (!)

您能给我一些提示(和代码示例)吗?我想以适当的方式学习这些东西,考虑到我很快就会转向 Core Data。

【问题讨论】:

Where to place the "Core Data Stack" in a Cocoa/Cocoa Touch application 的可能重复项 虽然您还没有处理 Core Data,但链接问题的答案讨论了您在应用程序中放置数据模型的各种替代方案,因此它们应该在这里应用。 谢谢布拉德,根据您的建议,我找到了一个很好的解决方案。我会尽快发布它作为我问题的答案。 【参考方案1】:

摘要:我仔细阅读了 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

我非常感谢对我的解决方案的任何评论,我渴望学习;)

【讨论】:

【参考方案2】:

更有经验的同事建议在 AppDelegate 中有相关的属性。 IMO 最好在特定控制器中使用特定的模型集。

【讨论】:

【参考方案3】:

我也是菜鸟,但这就是我所做的。最像 #2。

在 applicationDidFinishLaunching 中,应用委托创建模型的一个实例。

我的视图控制器声明了一个指向模型的属性,但类型是协议(在我的例子中是id &lt;GameModel&gt;。协议中的许多属性都声明为只读。

在 applicationDidFinishLaunching 中,应用委托将属性设置为指向它创建的模型。

我不喜欢的:

一个。您的视图控制器不必知道您的应用程序委托的结构。您可能会在另一个应用程序中使用不同的应用程序委托类型重用相同的视图控制器。您可以对视图控制器代码进行简单的更改来解决这个问题,或者有其他方法可以解决这个问题,但为什么要让它变得困难呢?

三个。我不像大多数人那样喜欢单身人士。问题是他们是单身。如果你想加载多个模型怎么办?

四个。 ?!?!

【讨论】:

你不应该有一个单例模型,但是你可以有一个单例来存储你的模型并允许它们被应用程序中的任何视图控制器检索......就像你的应用程序委托存储你的模型(应用程序委托毕竟是一个单例)

以上是关于如何处理 iOS 应用程序中的模型类的主要内容,如果未能解决你的问题,请参考以下文章

unity 中的线条类模型闪烁该如何处理?

如何处理iphone中的关键事件

如何处理ios目标c中的解析通知?

我应该如何处理 iOS 中的 ASIHTTPRequest 异步调用?

如何处理 iPhone 应用程序中的 NSError? [复制]

如何处理 iOS 远程消息中的附加数据 GCM