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

时间:2011-08-24 16:49:57

标签: iphone ios ipad model-view-controller model

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

我试图理解如何正确保存和引用模型对象。

  1. 很多人说要编写一个app delegate属性来保存模型,然后通过app delegate singleton的便捷方法引用它。
  2. 其他人说只在视图控制器中“注入”它所需要的模型部分(或其子视图需要),但我不明白如何做到这一点。通过财产?通过initWithModel:方法(在这种情况下,我怎么能说IB使用该方法?)
  3. 其他人再次说该模型应该是单身人士
  4. 再次,其他人说要使用全局变量(!)
  5. 你能给我一些提示(和代码示例)吗?我想以适当的方式学习这些东西,考虑到我将很快转向核心数据。

3 个答案:

答案 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类管理)。

让我们从模型的角度看看大计划是什么:

  1. 模型由Application委托实例化/加载为Product对象的NSMutableArray;
  2. 现在,通过属性将指向模型的指针传递给层次结构的第一个视图控制器UITableViewController。实际上,有人可能会争辩说层次结构中的第一个控制器是UINavigationController,所以我们应该将引用传递给它并将它传递给UITableViewController但是...... Apple说UINavigationController不应该是子类,所以我们不能添加任何属性/方法。实际上它是有道理的,因为UINavigationController的责任始终只是可视化管理,而不是模型操作。
  3. 当用户选择UITableCell时,UITableViewController会创建一个新的DetailViewController(带有关联的DetailView),将单个选定的产品作为属性传递,并将详细信息视图推送到UINavigation堆栈的顶部。
  4. 这里有一些代码片段:

    创建模型:

    // 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委托将属性设置为指向它创建的模型。

我不喜欢的事情:

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

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

四个。 ?!?!