正确的创build新对象的方法是在应用程序委托中定义的NSDictionary和NSArray对象的副本

我想知道什么正确的方法是在应用程序委托或单身人士对象中定义一个对象的副本。 总之,我正在制作一个需要用户login的应用程序。 这个login视图只是一个在“真实”应用程序之上的模式视图控制器,它由一个tabbarcontroller和一些tableview控制器组成。 成功login后,向远程服务器发送数据请求,模式视图控制器被解除,显示包含XML数据的TabBar控制器和表视图。 为了parsing传入的数据,我创build了一个名为DataParser的单例对象,它具有接口

... @interface DataParser : NSObject { // Data objects that hold the data obtained from XML files NSMutableDictionary *personnel; NSMutableDictionary *schedule; NSMutableDictionary *today; } @property (nonatomic, retain) NSMutableDictionary *personnel; @property (nonatomic, retain) NSMutableDictionary *schedule; @property (nonatomic, retain) NSMutableDictionary *today; ... 

现在,在这些字典中,我存储(可变的)字典和数组,其中包含了parsingXML数据的NSString对象。 由于我不想修改这些原始的对象来保存parsing的数据(也就是说,我只想在login阶段修改它们,而不是在任何的tableview控制器中修改),我正在创build一个新的字典对象,每个tableview控制器上面的一个字典的内容的副本。 所以例如,在一个名为ScheduleViewController的视图控制器的loadView中,我有

 ... @interface ScheduleViewController : UITableViewController { NSDictionary *copyOfSchedule; } @property (nonatomic, retain) NSDictionary *copyOfSchedule; ... @end @implementation ScheduleViewController @synthesize copyOfSchedule; - (void)loadView { [super loadView]; DataParser *sharedSingleton = [DataParser sharedInstance]; self.copyOfSchedule = [NSDictionary dictionaryWithDictionary:sharedSingleton.schedule]; } ... 

现在这似乎工作正常。 唯一的困难是,当用户“注销”时,需要将login模式视图控制器弹回堆栈。 当用户再次按下loginbutton时,一个新的XML数据请求被发送到服务器,单个对象中的字典被刷新(新)数据(我检查它们是否包含任何数据,如果是的话,我之前调用removeAllObjects用新parsing的数据填充它们)。 在这一点上,所有视图控制器中的字典都应该更新,但是我不太清楚如何以正确的方式进行操作。 我注意到在这种情况下loadView并不总是被再次调用,所以为此我在loadView中添加了与上面相同的代码给每个viewWillAppear方法。 在不同的视图之间来回导航或在一个tableview的子视图之间来回导航几次后,我收到一个EXC_BAD_ACCESS错误。 我怀疑这是与没有妥善保留原字典的副本有关,但我似乎无法find解决scheme。 而不是使用dictionaryWithDictionary,我怀疑是不是正确的方式去,无论如何,我也尝试了一种不同的方法,而不是在ScheduleViewController中使用NSDictionarytypes的对象,我使用NSMutableDictionary。 所以:

 ... @interface ScheduleViewController : UITableViewController { NSMutableDictionary *copyOfSchedule; } @property (nonatomic, retain) NSMutableDictionary *copyOfSchedule; ... @end @implementation ScheduleViewController @synthesize copyOfSchedule; - (void)loadView { [super loadView]; DataParser *sharedSingleton = [DataParser sharedInstance]; self.copyOfSchedule = [[NSMutableDictionary alloc] initWithDictionary:sharedSingleton.schedule]; } - (void)viewWillAppear { DataParser *sharedSingleton = [DataParser sharedInstance]; [self.copyOfSchedule removeAllObjects]; [self.copyOfSchedule addEntriesFromDictionary:sharedSingleton.schedule]; [self.tableView reloadData]; } ... 

但是这并没有摆脱EXC_BAD_ACCESS错误。 长话短说:在独立对象或应用程序委托中定义对象的独立副本,并且可以根据请求dynamic更新的最佳方法是什么? 由于我已经对这个项目有所了解,而且还有很多事情正在进行,我意识到我的问题可能有些模糊。 尽pipe如此,我希望有人能够以某种方式启发我。

深度拷贝通常是recursion的。 一种方法是将-deepCopy方法添加到NSDictionary和NSArray中。 字典版本可能是这样的:

 - (NSDictionary*)deepCopy { NSMutableDictionary *temp = [self mutableCopy]; for (id key in temp) { id item = [temp objectForKey:key]; if ([item respondsToSelector:@sel(deepCopy)] { // handle deep-copyable items, ie dictionaries and arrays [temp setObject:[item deepCopy] forKey:key] } else if ([item respondsToSelector:@(copy)]) { // most data objects implement NSCopyable, so will be handled here [temp setObject:[item copy] forKey:key]; } else { // handle un-copyable items here, maybe throw an exception } } NSDictionary *newDict = [[temp copy] autorelease]; [temp release] return newDict; } 

我没有testing过,所以要小心一点。 你会想为NSArray做类似的事情。

请注意,视图不可复制。

这是一个非常典型的模式,你用一些代码构build一个数组或字典,显然它必须是可变的,而你添加了一些代码,当你完成时,你不希望它改变。 去做这个:

有一个像财产

 @property (...) NSArray* myArray; 

当你计算myArray的内容时,使用一个可变数组来构build它

 NSMutableArray* myMutableArray = [NSMutableArray array]; 

当你完成构build数组时,只需使用

 self.myArray = [NSArray arrayWithArry:myMutableArray];