在类之间传递对象

Posted

技术标签:

【中文标题】在类之间传递对象【英文标题】:Passing Objects Between Classes 【发布时间】:2011-08-07 19:07:06 【问题描述】:

在我的 AppDelegate 中,我从 Internet 下载了一些数据并将其存储到一个数组中。我希望我的一个 ViewController 访问该数组。我该怎么做呢?这是实现委托或协议的好情况吗?如果是这样,有人可以为此推荐一个好的教程吗?

谢谢

编辑:

请注意,每次启动时数据都会刷新,因此不需要 Core Data 或 plist。此外,数据是我创建的自定义对象,因此它们不能存储在例如 plist 中。

【问题讨论】:

我认为答案取决于数据是否不可变并且仅在启动时加载一次(一次推送到视图控制器)或者数据是否可变并且需要通知感兴趣的视图更改( OBSERVABLE PUSH) 或者如果视图控制器需要从数据对象中按需提取数据。 真的有那么复杂吗,我认为我们可以深入了解用户想要实现的目标以及他想要解决的问题,我只是在他试图访问数据时读到他存储在他的应用程序委托中。是的,设计选择是有问题的,但纯粹基于提出的问题,它非常简单。 “我如何从我的应用程序的任何位置访问存储在我的应用程序委托中的数据” 【参考方案1】:

你有两个选择:

    实现委托协议 使用 NSNotifications

每个人的优点/缺点在这个问题和答案中都有很好的阐述: Delegates v Notifications

由于通知更容易实现并且可能足以满足您的需求,因此您可以通过以下步骤实现它:

    在您下载数据的类中: 下载数据并填充数组后,添加以下行:

NSDictionary *dict = [NSDictionary dictionaryWithObject:array forKey:@"Data"]; [[NSNotificationCenter defaultCenter] postNotificationName:@"DataDownloaded" object:self userInfo:dict];

    在您要接收数据的类中:

2.1 将以下行添加到您的 viewDidLoad 方法中:

`[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataDownloaded:) name:@"DataDownloaded" object:nil];

2.2 创建dataDownloaded选择器:

(void)dataDownloaded:(NSNotification *)note

NSDictionary *dict = note.userInfo; NSArray *dataArray = [note.userInfo objectForKey:@"DataDownloaded"];

2.3 将以下行添加到dealloc和viewDidUnload:

[[[NSNotificationCenter defaultCenter] removeObserver:self];

【讨论】:

我认为这并不能真正回答这个问题,OP 并没有表示他知道数据何时可用,但如何从他的应用程序的其他地方访问它有问题。就我个人而言,我发现通知的粒度有点粗,但往往适合应用程序的非功能部分,例如可达性。一些更好的代码设计可能会将数据封装在通过工厂接口(保持可测试性)提供的专用类中作为伪单例。【参考方案2】:

您可以将数据存储在 plist 文件中并在所有视图控制器中使用。这样,您就不必担心数据的大小(因为您将按需加载并立即释放它)。

【讨论】:

问题是我的数据不是 Foundation 的一部分。这是我创建的 plist 无法存储的自定义对象。此外,我不需要为此使用 Core Data,因为每次启动时数据都会刷新。 您可以存储在 plist 文件或 archives 中,而无需使用/知道 coredata。您需要做的就是使数据符合 NSCoding 协议。如果这不可能,我怀疑除了维护全局数据和处理同步之外,还有什么优雅的方法。【参考方案3】:

如果您想将您的数组存储在委托中,那么在任何视图中您都必须创建您的委托的引用,并且您可以在该视图中访问您的数组,如下所示:

在您的其他视图中,您必须在 .h 文件中写入:

#import "YourDelegateFile.h" 并声明一个变量

YourDelegateFile *appDelegate ;

在您的 .m 文件中:

- (void) viewDidLoad

   appDelegate = (YourDelegateFile *)[UIApplication sharedApplication] delegate];

   NSArray *aArray = [appDelegate yourArrayName]; //yourArrayName is an array that you have declare in delegate 

希望对你有帮助。

【讨论】:

这算是好的设计吗?听过好几次了,根本不推荐…… 它确实回答了原始海报的问题,尽管此代码可能无法正常工作,具体取决于选择器“yourArrayName”是什么【参考方案4】:

您只需要访问存储在 appdelegate 中的数据。我不认为这是解决您的问题的最佳方法,但为了按照您想要的方式做事。

所以在你的 Appdelegate .h 文件中声明你的属性

NSMutableArray* myArray_;

然后在同一个文件中添加一个属性

@property (nonatomic, retain) NSMutableArray* myArray;

在.m文件中

确保你合成了你的属性

@synthesize myArray = myArray_;

您将在 appdelegate .m 文件的某个位置设置值

然后,在代码的其他地方,您可以像这样访问 appdelegate 中的属性

MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate
NSMutableArray* localArray = appDelegate.myArray;

注意,为了良好的封装,您应该真正使用 NSArray,但我使用 mutable 来保持代码简短。

另外,使用 appdelegate 作为程序数据的全局存储也不是一个好主意,它打破了很多你不应该打破的规则,单一责任原则是一个很好的开始。理想情况下,您应该将应用程序数据存储在专用类中,可能是单例,或者为了更好的可测试性,由工厂类提供的单个实例类。通过这种方式,您的数据可以从已知的定义良好的实体访问,它是可测试的,并且符合良好的设计原则

【讨论】:

就我而言,你会推荐一个单例类吗?基本上我有一个 10 个频道的列表。对于每个频道,我需要存储三件事:现在、下一个和以后。那么像单例类中的两个嵌入式 NSDictionaries 之类的东西会这样做吗?请注意,我也在谈论好的设计。对我来说,好的设计与功能一样重要。 单身人士是有争议的,请参阅这篇文章ibm.com/developerworks/webservices/library/co-single/index.html他们确实有自己的位置,但他们打破了许多良好的做法,例如单一责任原则,因为他们对他们提供的功能负责您的应用程序以及管理只有一个实例这一事实,它们也使测试变得困难。有一些更精细的方法可以使用工厂来更好地设计事物来管理单例。整本书都可以专门讨论这个主题,我建议阅读它.. 就个人而言,现在、下一个和以后的唯一区别是您查看该数据的时间,尽管这对您如何请求数据以及如何返回数据做出了假设。为什么不将通道建模为它负责了解其程序的对象,然后进行一些操作来确定现在、下一个或以后哪个是,您可能需要一个包含通道对象的 channelManager 类,您可能还会发现它有助于将请求建模为对象,并围绕该对象构建一些代码以发出请求和处理响应。由你决定【参考方案5】:

如果应用代理获得了新数据,您可以发送通知,并且所有感兴趣的控制器都会知道他们需要更新视图。为此,您可以使用NSNotificationCenter。例如

- (void)newDataLoaded 
  NSDictionary *userInfo = [NSDictionary dictionaryWithObject:arrayOfData forKey:@"data"];
  [[NSNotificationCenter defaultCenter] postNotificationName:@"data updated notification name" object:nil userInfo:userInfo];

如果某些控制器对数据更新感兴趣,它应该尽快订阅此通知:

- (void)viewDidLoad 
  ...
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataUpdatedNotificationHandler:) name:@"data updated notification name" object:nil];
  ...

如果您不需要通知,请不要忘记取消订阅。为此在viewDidUnloaddealloc 方法中使用[[NSNotificationCenter defautCenter] removeObserver:self]

- (void)dataUpdatedNotificationHandler:(NSNotification*)notification 
  NSArray *data = [[notification userInfo] objectForKey:@"data"];
  // update your view here

【讨论】:

以上是关于在类之间传递对象的主要内容,如果未能解决你的问题,请参考以下文章

如何在类层次结构中传递智能指针

16. 在.NET中,一个页面对象是( )类的实例。

python 面向对象专题:类的空间问题类与对象之间的关系类与类之间的关系

python 面向对象专题:类的空间问题类与对象之间的关系类与类之间的关系

Python -- 面向对象:类空间问题以及类之间的关系

内省(Introspector)