UIViewController State Restoration - weak relationships
Asked Answered
T

1

8

With iOS 6 Apple added state restoration to UIViewController and related classes. This allows the application to save state when terminated and restore it when the user resumes the application.

Everything seems to work fine, however I have reached a weird scenario which doesn't want to fit into the pattern.

Let's assume we have two view controllers, ViewControllerOne and ViewControllerTwo, both of them store some arbitrary state that is restored successfully. Now let's imagine that ViewControllerOne has a delegate property and that ViewControllerTwo is that delegate (which is a common pattern for modal view controllers). Who is responsible for restoring this relationship? And how is it supposed to be stored/restored?

In my particular case no storyboards are involved, the restoration happens in code, via the restorationClass property. My first instinct was to try and restore the relationship whilst creating the view controller in the restorationClass, however as the restorationClass has no idea of other existing controllers it can't quite restore such a relationship.

Alternatively, if it is the view controller that declares the delegate property, that is supposed to restore the relationship, then how does it now of the controller instance that was restored in some other class?

In short, this seems like a poorly documented scenario and I was hoping someone could shed some light on it.

Truthfunction answered 18/12, 2013 at 18:15 Comment(0)
U
3

I would say, the task falls on the delegate view controller to set itself as such, just like you do it before pushing the other view controller.

On how you can accomplish this, you have several options.

You can store a weak reference to your view controllers in a globally accessible location (for example, the app delegate), and use these values in application:didDecodeRestorableStateWithCoder: to set the delegation - this is what this method is for in the API.

Alternatively, you could post a "hereIAmThisIsMe" notification (with self part of the user info) from the top view controller to which the delegate listens and sets itself as a delegate.

Unscrupulous answered 20/12, 2013 at 22:14 Comment(9)
Although this is definitely a plausible way of doing things, wouldn't you agree that it is not the most elegant? i.e it feels like the first proposed solution breaks encapsulation a bit (AppDelegate becomes this "know it all", not something you want)? The second is a bit more interesting approach, where would you send this notification, in the decodeRestorableStateWithCoder:?Truthfunction
Sending there is an option, but you have to worry about timing - which controller is restored first.Alo
@HenriNormak BTW, the first method does not necessarily break encapsulation. You could implement a protocol, let's call it PostRestorationHandler, where there is a method didFinishRestoration, and have the delegate view controller set up delegation there. The AppDelegate only knows about the existence if the view controllers (and they about the app delegate), but it doesn't touch internals.Alo
Liking that approach, however, what if instead of having a protocol and the AppDelegate as the caller for that, I'd have a notification that is fired when application delegate gets the didDecode... callback. This way each controller could restore their own relationships (assuming they stored the reference) the way you described.Truthfunction
@HenriNormak, that is possible, but again, the problem with notifications is dependency on order. It would work if only one has to do something, but, for example, if you need the second VC to call a delegate method, it would be an "oops" if it is notified first and the delegate is still not set.Alo
Although I am not fully satisfied with the answer, it does indeed work and sadly no other suggestions came up, so marked as accepted.Truthfunction
@HenriNormak Thanks. Which method did you decide to go with?Alo
I slightly adjusted the "didFinishRestoration" approach and went with that. However, instead of doing everything in the app controller, I do it in the controller that is presenting the delegated controller. In my testing it seems that the decoding happens from the deepest level first, so in there the relationship can be re-determined. Currently I just handle it based on -presentedViewController and checking whether it has a -delegate property.Truthfunction
@HenriNormak Be careful with this approach. It could break whenever Apple decides to change stuff in there.Alo

© 2022 - 2024 — McMap. All rights reserved.