我正在使用NSUserDefaults
来保持对象在UIViewController
中使用的几个UITabbarController
之间保持同步。为此,我正在实施以下
- (void)viewWillAppear:(BOOL)animated
{
NSLog(@"ViewControllerX Will Appear");
[super viewWillAppear:animated];
NSDictionary *dict = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"sharedDictionary"];
[customObject setDictionary:dict];
}
- (void)viewWillDisappear:(BOOL)animated
{
NSLog(@"ViewControllerX Will Disappear");
NSDictionary *dict = [customObject dictionary];
[[NSUserDefaults standardUserDefaults] setObject:dict forKey:@"sharedDictionary"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
此处customObject
是自定义类的实例,其属性dictionary
的类型为NSDictionary
。可见UIViewController
可能会更改此对象。
我目前遇到的问题是当用户切换标签时,例如从ViewControllerX
到ViewControllerY
,这些方法不会按预期顺序调用。我希望在日志中看到这一点:
ViewControllerX Will Disappear
ViewControllerY Will Appear
但我看到了
ViewControllerY Will Appear
ViewControllerX Will Disappear
结果是旧字典加载到ViewControllerY
中,并且只有在再次切换标签后才会出现新字典。这个问题有一个简单的方法吗?
答案 0 :(得分:5)
无法保证调用这些方法的顺序,因此您不能依赖它们的任何顺序。您唯一可以保证在视图显示或消失之前调用-viewWillAppear:
和-viewWillDisappear:
。
处理此问题的另一种方法可能是将此更改为意愿/确实类型方案。因此,您可以在-viewWillDisappear:
中保存对象的当前状态,并在-viewDidAppear:
中恢复状态(即加载字典)。这将保证正在消失的视图在显示的视图之前保存其字典。
另一种方法是更改自定义词典在视图控制器之间传递的方式,并使用应用程序UITabBarViewController
上的委托对象来处理将这些更改同步到用户默认值。您可以将其集成到您的应用中但是最有意义,但我将在下面提供一个基本示例以及您需要为您的应用提供的更改(如您的问题中所述):
要使用该示例,您需要进行这些更改(适应您的编码风格):
NSDictionary
添加到名为_sharedDictionary
的ivar到您的应用程序代理UITabBarControllerDelegate
协议UITabBarController
的代表。sharedDictionary
-viewWillAppear
中将视图控制器的sharedDictionary
属性的值设置为自定义对象,并像以前一样继续完成这些操作后,将以下方法实现添加到您的app delegate:
-(BOOL)tabBarController:(UITabBarController*)tabBarController shouldSelectViewController:(UIViewController*)viewController
{
// If you're using ARC, you can remove the retain/autorelease statements
[_sharedDictionary autorelease];
// In order to avoid a compiler warning here, you should have your view controllers
// possibly inherit from a parent that defines the sharedDictionary property and cast
// to that, or have your view controllers implement a protocol that defines the
// property, and cast to that. As long as your view controllers actually implement
// the sharedDictionary property, however, everything will work
_sharedDictionary = [[[tabBarController selectedViewController] sharedDictionary] retain];
// set the shared dictionary on the new view controller -- same casting rules apply
// as stated above
[viewController setSharedDictionary:_sharedDictionary];
// save this to user defaults so that if the app stops, it maintains whatever state
// you're keeping
dispatch_async(dispatch_get_main_queue(), ^{
[[NSUserDefaults standardUserDefaults] setObject:_sharedDictionary forKey:@"sharedDictionary"];
[[NSUserDefaults standardUserDefaults] synchronize];
});
return YES;
}
答案 1 :(得分:2)
这很简单。而不是每个视图控制器都有自己的CustomObject副本,并试图通过NSUserDefaults使它们保持同步,让两个视图控制器共享同一个CustomObject实例。
此外,您还可以尝试使用Observer设计模式。您的视图控制器将扮演Observer的角色,而单个CustomObject实例将扮演Subject的角色。
有关将customObject
状态保存到用户默认值/从用户默认值加载的详细信息应封装在customObject
内,并从视图控制器中隐藏。您的视图控制器不需要知道 customObject
如何在用户默认值中保存/加载NSDictionnary
。你的customObject
课程应该是这样的:
@interface CustomClass : NSObject
@property (nonatomic, strong) NSString* name;
@property (nonatomic, assign) float value;
- (void)save;
- (void)load;
// Other methods
@end
@implementation CustomClass
@synthesize name = name_;
@synthesize value = value_;
- (void)save
{
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
name_, @"Name",
[NSNumber numberWithFloat:value_], @"Value",
nil];
[[NSUserDefaults standardUserDefaults] setObject:dict
forKey:@"CustomObject"];
}
- (void)load
{
NSDictionary* dict = [[NSUserDefaults standardUserDefaults]
objectForKey:@"CustomObject"];
name_ = [dict objectForKey:@"Name"];
NSNumber* valueNum = [dict objectForKey:@"Value"];
value_ = [valueNum floatValue];
}
@end
应用程序启动时应加载customObject
一次。您可以在AppDelegate的didFinishLaunchingWithOptions
方法中执行此操作:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[sharedCustomObject load];
}
在视图控制器“viewWillAppear
中,您无需重新加载sharedCustomObject
。 它已经保持当前状态。
在您的视图控制器“viewWillDisappear
中,您只需确保用户默认值中sharedCustomObject
的状态备份。
- (void)viewWillDisappear:(BOOL)animated
{
[sharedCustomObject save];
}
保存后,sharedCustomObject
仍然是最新的,无需重新加载。
我希望现在事情更清楚了。 : - )
答案 2 :(得分:0)
我可能不会以这种方式使用NSUserDefaults
。您应该能够在给定的视图控制器中封装行为,而不是依赖特定的执行路径来操作共享状态。要么使用Jason的viewDidAppear
建议,要么将ViewControllerX
的字典内部副本直接传递到ViewControllerY
,以避免不得不解决它。