Восстановление состояния UIViewController — слабые отношения

В iOS 6 Apple добавила восстановление состояния в UIViewController и связанные с ним классы. Это позволяет приложению сохранять состояние при завершении и восстанавливать его, когда пользователь возобновляет работу приложения.

Кажется, все работает нормально, однако я столкнулся со странным сценарием, который не хочет вписываться в шаблон.

Предположим, у нас есть два контроллера представления, ViewControllerOne и ViewControllerTwo, оба они хранят некоторое произвольное состояние, которое успешно восстанавливается. Теперь давайте представим, что ViewControllerOne имеет свойство delegate и что ViewControllerTwo является этим делегатом (что является общим шаблоном для контроллеров модального представления). Кто несет ответственность за восстановление этих отношений? И как его хранить/восстанавливать?

В моем конкретном случае никакие раскадровки не задействованы, восстановление происходит в коде через свойство restorationClass. Моим первым побуждением было попытаться восстановить отношения при создании контроллера представления в restoreClass, однако, поскольку restorationClass не знает о других существующих контроллерах, он не может полностью восстановить такие отношения.

В качестве альтернативы, если это контроллер представления, который объявляет свойство delegate, которое должно восстановить отношение, то как теперь он относится к экземпляру контроллера, который был восстановлен в каком-то другом классе?

Короче говоря, это похоже на плохо задокументированный сценарий, и я надеялся, что кто-то сможет пролить на него свет.


person Henri Normak    schedule 18.12.2013    source источник


Ответы (1)


Я бы сказал, задача ложится на делегированный контроллер представления, чтобы установить себя как таковой, точно так же, как вы делаете это перед нажатием другого контроллера представления.

О том, как вы можете это сделать, у вас есть несколько вариантов.

Вы можете хранить слабую ссылку на свои контроллеры представления в глобально доступном месте (например, в делегате приложения) и использовать эти значения в application:didDecodeRestorableStateWithCoder: для установки делегирования — для этого этот метод и предназначен в API.

В качестве альтернативы вы можете опубликовать уведомление «hereIAmThisIsMe» (с self частью информации о пользователе) из контроллера верхнего представления, который слушает делегат и устанавливает себя в качестве делегата.

person Leo Natan    schedule 20.12.2013
comment
Хотя это, безусловно, правдоподобный способ ведения дел, не согласитесь ли вы, что он не самый элегантный? то есть кажется, что первое предложенное решение немного нарушает инкапсуляцию (AppDelegate становится всезнайкой, а не тем, что вам нужно)? Второй подход немного интереснее, куда бы вы отправили это уведомление, в файле decodeRestorableStateWithCoder:? - person Henri Normak; 21.12.2013
comment
Отправка есть вариант, но надо побеспокоиться о сроках - какой контроллер восстанавливается первым. - person Leo Natan; 21.12.2013
comment
@HenriNormak Кстати, первый метод не обязательно нарушает инкапсуляцию. Вы можете реализовать протокол, назовем его PostRestorationHandler, где есть метод didFinishRestoration, и настроить там делегирование делегирования контроллера представления делегата. AppDelegate знает только о существовании контроллеров представления (и они о делегате приложения), но не затрагивает внутренности. - person Leo Natan; 21.12.2013
comment
Однако мне нравится этот подход: что, если вместо протокола и AppDelegate в качестве вызывающей стороны для этого у меня будет уведомление, которое срабатывает, когда делегат приложения получает обратный вызов didDecode.... Таким образом, каждый контроллер может восстановить свои собственные отношения (при условии, что они сохранили ссылку) так, как вы описали. - person Henri Normak; 21.12.2013
comment
@HenriNormak, это возможно, но опять же, проблема с уведомлениями заключается в зависимости от порядка. Это будет работать, если только один должен что-то сделать, но, например, если вам нужен второй VC для вызова метода делегата, это будет oops, если он будет уведомлен первым, а делегат все еще не установлен. - person Leo Natan; 21.12.2013
comment
Хотя я не полностью удовлетворен ответом, он действительно работает, и, к сожалению, никаких других предложений не поступало, поэтому они были отмечены как принятые. - person Henri Normak; 25.12.2013
comment
@HenriNormak Спасибо. Какой метод вы решили использовать? - person Leo Natan; 25.12.2013
comment
Я немного подкорректировал подход didFinishRestoration и остановился на этом. Однако вместо того, чтобы делать все в контроллере приложения, я делаю это в контроллере, представляющем делегированный контроллер. В моем тестировании кажется, что декодирование сначала происходит с самого глубокого уровня, поэтому там отношения могут быть переопределены. В настоящее время я просто обрабатываю его на основе -presentedViewController и проверяю, есть ли у него свойство -delegate. - person Henri Normak; 25.12.2013
comment
@HenriNormak Будьте осторожны с таким подходом. Он может сломаться, когда Apple решит что-то там изменить. - person Leo Natan; 25.12.2013