如何在Objective-C中在视图控制器之间传递对象?

5

我花了两天时间仔细查看代码,试图找出为什么无法获取在.h文件中声明、在.m文件中实现并在viewDidLoad函数中设置的全局NSMutableArray变量。

最后我意识到:在Objective-C中没有全局变量,至少不是我所熟悉的PHP那种。我从来没有真正阅读过XCode的错误警告,但即使不是很明显,“Instance variable 'blah' accessed in class method.”也存在于其中。

我的问题是:现在该怎么办?我有两个视图控制器需要访问一个中央NSMutableDictionary,它是通过URL从JSON文件生成的。它基本上是我所有Table View下钻的扩展菜单,并且我想有其他一些“全局”(非静态)变量。

我是否必须每次都获取JSON以生成这个NSMutableDictionary,还是有一种通过#import设置一次并从各个类访问的方法?我是否必须将数据写入文件,或者人们通常采用其他方式处理这个问题?


1
“Instance variable 'blah' accessed in class method.” 这个错误提示了一个不同的问题:这意味着你有一个类方法(以“+”开头)试图引用一个实例变量。由于类方法在定义上与类的任何特定实例都没有关联,它们无法访问实例变量。 - David Gelhar
4个回答

9

如果你有两个访问共享NSMutableDictionary的视图控制器,你能否将指向公共字典的指针传递到它们各自的初始化消息中?

因此,在你的AppDelegate中:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
  // the app delegate doesn't keep a reference this, it just passes it to the 
  // view controllers who retain the data (and it goes away when both have been released)
  NSMutableDictionary * commonData = [[NSMutableDictionary new] autorelease];

  // some method to parse the JSON and build the dictionary
  [self populateDataFromJSON:commonData];

   // each view controller retains the pointer to NSMutableDictionary (and releases it on dealloc)
   self.m_viewControllerOne = [[[UIViewControllerOne alloc] initWithData:commonData] autorelease];
   self.m_viewControllerTwo = [[[UIViewControllerTwo alloc] initWithData:commonData] autorelease];
}

在您各自的UIViewControllerOne和UIViewControllerTwo实现中。
- (id)initWithData:(NSMutableDictionary*)data
{
    // call the base class ini
    if (!(self=[super init]))
        return nil;

    // set your retained property
    self.sharedData = data;
}

// don't forget to release the property
- (void)dealloc {
    [sharedData release];
    [super dealloc];
}

有趣!我不知道你可以使用initWithData分配一个UIViewController类。我在几个地方读到过,在AppDelegate中这样做有点hackish。那是胡说八道吗? - buley
“initWithData”消息不是UIViewController中的标准消息。这是您需要添加到您的UIViewControllers中以处理传递数据的内容(因此,您可以向此消息添加任何参数)。我会修改我的答案以澄清这一点。 - RedBlueThing
谢谢。我相信这是我能得到的最好的答案。我仍在努力理解它。如果有相关的后续问题,希望您不介意我提问。 - buley
没问题。很乐意帮忙 :) - RedBlueThing

2
实际上,您可以通过多种方式实现此操作(而不必采用像写入文件这样极端的方法)。您可以使用以下方式创建“全局”:
  1. 老式C全局变量(externs)
  2. 单例
  3. 应用程序委托中的实例变量
但是,所有这些方法都会使您的视图控制器 less模块化(因为它们依赖于到达“外部”以查找全局数据),因此最好的方法可能是将字典作为视图控制器类的属性,并由调用者显式设置(在initWithDictionary:方法中或使用单独的setter)。

什么是单例类?(对不起,我很无知。再说一次:我是个糟糕的 PHP 程序员。) - buley
“Singleton”只是一个类的花哨名称,它仅实例化一次(我会在我的答案中添加一个链接)。例如,您可能有一个名为“MySingleton”的类,其中包含一个sharedInstance类方法,该方法返回该(单个)实例。然后,您可以调用共享实例上的方法,例如:[[MySingleton sharedInstance] setFoo:@"foo"] - David Gelhar
谢谢,非常清晰。同时,感谢您对我上面原始问题的非常有帮助的评论。 - buley
有关单例模式的更多信息,请阅读此问题:https://dev59.com/JHVC5IYBdhLWcg3w7Vxq - John

1

只需创建一个全局变量。全局意味着在任何作用域之外。

NSMutableDictionary *gDictionary;

@implementation ...
@end

那会很棒,但似乎对我不起作用。我会继续尝试。 - buley

1

在 Obj-C 中有全局变量,你可以在 App Delegate 中实例化它们。

但是针对你的问题,当你实例化新的视图控制器时,你可能想要传递 NSMutableDictonary,就像这样 [UIView alloc] initWithDictionary:(NSMutableDictionary *)dict; 如果你知道我的意思的话。

在你的示例中,你是否有一个类调用另一个类?我认为应该有某种控制器来确定要显示哪个视图控制器,并且那里是访问和传递字典的地方。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接