Iphone 这将是一场灾难

Iphone 这将是一场灾难,iphone,ios,nsuserdefaults,Iphone,Ios,Nsuserdefaults,我使用NSUserDefaults在UIAbbarController中使用的多个UIViewController中保持对象同步。为此,我将实现以下内容 - (void)viewWillAppear:(BOOL)animated { NSLog(@"ViewControllerX Will Appear"); [super viewWillAppear:animated]; NSDictionary *dict = [[NSUserDefaults standardUs

我使用
NSUserDefaults
UIAbbarController
中使用的多个
UIViewController
中保持对象同步。为此,我将实现以下内容

- (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
是一个自定义类的实例,该类具有类型为
NSDictionary
的属性
dictionary
。此对象可能会被visible
UIViewController
更改

我现在遇到的问题是,当用户切换选项卡时,比如从
ViewControllerX
切换到
ViewControllerY
,这些方法不会按预期顺序被调用。我希望在日志中看到这一点:

ViewControllerX Will Disappear
ViewControllerY Will Appear
但是我看到

ViewControllerY Will Appear
ViewControllerX Will Disappear

结果是,旧词典加载到
ViewControllerY
,只有在再次切换选项卡后,新词典才会出现。有没有一种简单的方法可以解决这个问题?

无法保证调用这些方法的顺序,因此您不能依赖于它们的任何顺序。您得到的唯一保证是,在视图出现或消失之前,将分别调用
-view:
-view:

另一种处理方法可能是将其更改为will/did类型的场景。因此,您将对象的当前状态保存在
-viewWillEnglish:
中,并在
-viewDidDisplay:
中恢复状态(即加载词典)。这将确保即将离开的视图在出现视图之前保存其词典

另一种方法是更改在视图控制器之间传递自定义词典的方式,并在应用程序的
UITabBarViewController
上使用委托对象来处理将这些更改同步到用户默认值的问题。您可以将其集成到您的应用程序中,但这是最有意义的,但我将在下面提供一个基本示例,以及您需要对应用程序进行的更改(如问题中所述):

要使用该示例,您需要进行以下更改(适应您的编码风格):

  • 将名为
    \u sharedDictionary
    NSDictionary
    添加到应用程序委托的ivar中
  • 当应用程序启动时,从用户默认值加载字典
  • 声明您的应用程序代理实现了
    uitabarcontrollerdelegate
    协议
  • 加载应用程序时,将应用程序代理指定为主
    UITabBarController
    的代理
  • 更改视图控制器以响应可调用的新属性
    sharedDictionary
  • 您可以在
    -view将出现的地方维护代码的其余部分
    将视图控制器的
    sharedDictionary
    属性的值设置为自定义对象,然后继续之前的操作
完成这些操作后,将以下方法实现添加到应用程序代理中:

-(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;
}

无法保证调用这些方法的顺序,因此不能依赖于它们的任何顺序。您得到的唯一保证是,在视图出现或消失之前,将分别调用
-view:
-view:

另一种处理方法可能是将其更改为will/did类型的场景。因此,您将对象的当前状态保存在
-viewWillEnglish:
中,并在
-viewDidDisplay:
中恢复状态(即加载词典)。这将确保即将离开的视图在出现视图之前保存其词典

另一种方法是更改在视图控制器之间传递自定义词典的方式,并在应用程序的
UITabBarViewController
上使用委托对象来处理将这些更改同步到用户默认值的问题。您可以将其集成到您的应用程序中,但这是最有意义的,但我将在下面提供一个基本示例,以及您需要对应用程序进行的更改(如问题中所述):

要使用该示例,您需要进行以下更改(适应您的编码风格):

  • 将名为
    \u sharedDictionary
    NSDictionary
    添加到应用程序委托的ivar中
  • 当应用程序启动时,从用户默认值加载字典
  • 声明您的应用程序代理实现了
    uitabarcontrollerdelegate
    协议
  • 加载应用程序时,将应用程序代理指定为主
    UITabBarController
    的代理
  • 更改视图控制器以响应可调用的新属性
    sharedDictionary
  • 您可以在
    -view将出现的地方维护代码的其余部分
    将视图控制器的
    sharedDictionary
    属性的值设置为自定义对象,然后继续之前的操作
完成这些操作后,将以下方法实现添加到应用程序代理中:

-(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;
}

我可能不会那样使用
NSUserDefaults
。您应该能够在给定的视图控制器中封装行为,而不依赖特定的执行路径来操纵共享状态。要么使用Jason建议的
viewdideappear
,要么将
ViewControllerX
的词典内部副本直接传递到
ViewControllerY
中,以避免必须解决它。

我可能不会以这种方式使用
NSUserDefaults
。您应该能够在给定的视图控制器中封装行为,而不依赖特定的执行路径来操纵共享状态。使用Jason建议的
viewdideappear
或将
ViewControllerX
的词典内部副本直接传递到
ViewControllerY
中,以避免需要解决它。

这很简单。而不是每个视图控制器都有自己的CustomObject副本并试图保持它们的同步
- (BOOL)application:(UIApplication *)application
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [sharedCustomObject load];
}
- (void)viewWillDisappear:(BOOL)animated
{
    [sharedCustomObject save];
}