查看将出现的困境
我使用 NSUserDefaults
来使对象在 UITabbarController
中使用的多个 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
。该对象可能会被可见的 UIViewController 改变。
我当前遇到的问题是,当用户切换选项卡时,例如从 ViewControllerX 切换到 ViewControllerY 时,这些方法不会按预期顺序调用。我希望在日志中看到这一点:
ViewControllerX Will Disappear
ViewControllerY Will Appear
但我看到的
ViewControllerY Will Appear
ViewControllerX Will Disappear
结果是旧字典被加载到 ViewControllerY 中,只有再次切换选项卡后才会出现新字典。有一个简单的方法可以解决这个问题吗?
I'm using NSUserDefaults
to keep an object in sync across several UIViewController
s that are used in a UITabbarController
. To do this, I'm implementing the following
- (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];
}
Here customObject
is an instance of a custom class that has a property dictionary
of type NSDictionary
. This object may get changed by the visible UIViewController
.
The problem I current have is that when the user switches tabs, say from ViewControllerX
to ViewControllerY
, these methods aren't getting called in the expected order. I expect to see this in the log:
ViewControllerX Will Disappear
ViewControllerY Will Appear
but instead I see
ViewControllerY Will Appear
ViewControllerX Will Disappear
The result is that the old dictionary is loaded in ViewControllerY
, and only after switching tabs again does the new dictionary appear. Is there an easy way around this problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
无法保证这些方法将以何种顺序被调用,因此您不能依赖它们的任何顺序。您得到的唯一保证是
-viewWillAppear:
和-viewWillDisappear:
将分别在视图出现或消失之前被调用。处理此问题的另一种方法可能是将其更改为 will/did 类型场景。因此,您可以在
-viewWillDisappear:
中保存对象的当前状态,并在-viewDidAppear:
中恢复状态(即加载字典)。这将保证即将消失的视图在出现的视图之前保存其字典。另一种方法是更改自定义字典在视图控制器之间传递的方式,并在应用程序的 UITabBarViewController 上使用委托对象来处理将这些更改同步到用户默认值。您可以将其集成到您的应用程序中,但是最有意义,但我将在下面提供一个基本示例以及您需要向应用程序提供的更改(如您的问题中所述):
要使用该示例,您需要要进行这些更改(适应您的编码风格):
NSDictionary
添加到名为_sharedDictionary
的 ivar 到您的应用程序委托,UITabBarControllerDelegate
协议UITabBarController
的委托。sharedDictionary
的新属性,-viewWillAppear
中设置视图控制器的 < code>sharedDictionary 属性添加到您的自定义对象中,然后像之前一样继续完成这些操作后,将以下方法实现添加到您的应用程序委托中:
There's no guarantee which order these methods are going to be called in, so you can't rely on any ordering with them. The only guarantee you get is that
-viewWillAppear:
and-viewWillDisappear:
will be called before the view appears or disappears respectively.Another way to deal with this might be changing this to a will/did type scenario. So, you save the current state of your object in
-viewWillDisappear:
and you restore the state (i.e., load your dictionary) in-viewDidAppear:
. This will guarantee that the view that is going away saves its dictionary before the view that appears.Another approach would be to change the way the custom dictionary is passed between your view controllers and use a delegate object on your application's
UITabBarViewController
to deal with syncing these changes to the user defaults. You can integrate this into your app however makes the most sense, but I'll provide a basic example below along with the changes you'd need to provide to your app (as described in your question):To use the example, you need to make these changes (adapt to your coding style):
NSDictionary
to ivar named_sharedDictionary
to your application delegateUITabBarControllerDelegate
protocolUITabBarController
.sharedDictionary
-viewWillAppear
you set the value of the view controller'ssharedDictionary
property to your custom object and just continue as you did beforeAfter you've done those things, add the following method implementation to your app delegate:
这很简单。让两个视图控制器共享同一个 CustomObject 实例,而不是让每个视图控制器拥有自己的 CustomObject 副本并尝试通过 NSUserDefaults 使它们保持同步。
此外,您还可以尝试使用观察者设计模式。您的视图控制器将扮演观察者的角色,而单个 CustomObject 实例将扮演主题的角色。
将
customObject
状态保存到用户默认值/从用户默认值加载的详细信息应封装在customObject
内,并对视图控制器隐藏。您的视图控制器不需要知道如何customObject
将NSDictionnary
保存到用户默认值/从用户默认值加载。您的customObject
类应如下所示:您的
customObject
应在应用程序启动时加载一次。您可以在 AppDelegate 的didFinishLaunchingWithOptions
方法中执行此操作:在视图控制器的
viewWillAppear
中,您不需要重新加载sharedCustomObject
本身。 它将已经保持当前状态。在视图控制器的
viewWillDisappear
中,您只需确保sharedCustomObject
的状态在用户默认值中为备份。保存后,
sharedCustomObject
仍然是最新的,不需要重新加载。我希望事情现在更清楚了。 :-)
It's simple. Instead of each view controller having their own copy of CustomObject and trying to keep them in sync via NSUserDefaults, have both view controllers share the same instance of CustomObject.
In addition, you might also try using the Observer design pattern. Your view controllers would play the role of Observer, and a single CustomObject instance would play the role of Subject.
The details on saving/loading
customObject
's state to/from user defaults should be encapsulated insidecustomObject
and hidden from your view controllers. Your view controllers should not need to know howcustomObject
save/loads aNSDictionnary
to/from user defaults. YourcustomObject
's class should look something like this:Your
customObject
should be loaded once when your application starts. One place you can do this is in your AppDelegate'sdidFinishLaunchingWithOptions
method:In your view controllers'
viewWillAppear
, you don't need to makesharedCustomObject
reload itself. It will already hold the current state.In your view controllers'
viewWillDisappear
, you only need to make sure thatsharedCustomObject
's state is backed-up in the user defaults.After saving,
sharedCustomObject
is still up-to-date and does not need to be reloaded.I hope things are clearer now. :-)
我可能不会以这种方式使用 NSUserDefaults 。您应该能够将行为封装在给定的视图控制器中,而不是依赖于特定的执行路径来操作共享状态。要么使用 Jason 的
viewDidAppear
建议,要么将ViewControllerX
的字典内部副本直接传递到ViewControllerY
以避免解决该问题。I wouldn't use
NSUserDefaults
in that way, probably. You should be able to encapsulate behaviour in a given view controller and not rely on a particular execution path to manipulate shared state. Either use Jason's suggestion ofviewDidAppear
or passViewControllerX
's internal copy of the dictionary straight intoViewControllerY
to avoid having to work around it.