Сохранение состояния для контроллеров представления с пользовательскими делегатами или источниками данных
Я пытаюсь использовать iOS 6+ (мое приложение 7.0+), сохранение состояния, чтобы сохранить представление, которое представлено модально из другого View Controller. Как таковой, он имеет типичный образец отклонения контроллера модального представления:
TNTLoginViewController.h содержит
@protocol TNTLoginViewControllerDelegate <NSObject>
- (void)TNTLoginViewControllerDismiss:(TNTLoginViewController *)controller;
@end
@interface TNTLoginViewControllerDelegate : NSObject
@interface TNTLoginViewController : UIViewController
@property (weak, nonatomic) IBOutlet id <TNTLoginViewControllerDelegate> delegate;
- (IBAction)getStarted:(id)sender;
@end
getStarted: реализация
- (IBAction)getStarted:(id)sender
{
// Perform login
...
// Dismiss me
[self.delegate TNTLoginViewControllerDismiss:self];
}
TNTLoginViewControllerDismiss: метод на делегате, который представил модальное
- (void)TNTLoginViewControllerDismiss:(TNTLoginViewController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
И все это работает как шарм! До сохранения государства. Проще говоря, я не знаю, как TNTLoginViewController сохранит свой делегат. Я понимаю, почему это не может: это просто указатель! Поэтому я попробовал различные способы получения делегата:
- Восстановление класса: к сожалению, как метод класса,
viewControllerWithRestorationIdentifierPath:coder:
не помогает мне указать на мое конкретное представление View Controller. - Установите мое представление VC в качестве делегата моего модального VC в Storyboard: Xcode не позволил бы мне нарисовать это соединение, даже когда мой класс VC публично принял
TNTLogingViewControllerDelegate>
Протокол в его заголовке. Это может быть отдельной проблемой, или это может быть запрещено. - Используйте уровень приложения-делегата
application:viewControllerWithRestorationIdentifierPath:coder:
вернуть модальный контроллер представления с его делегатом, установленным для моего представления View Controller. Я должен быть в состоянии получить это представление VC от делегата приложения, но это может сработать.
Сейчас я иду с № 3, но если есть лучшее решение, которое кто-то может порекомендовать, я был бы в восторге.
Установки, которые привели бы к подобным проблемам:
- Настройка источника данных, скажем, для табличного представления.
1 ответ
Вы правы, это можно сделать на уровне приложения-делегата с application:viewControllerWithRestorationIdentifierPath:coder:
, но вы должны быть осторожны / умны в том, как вы это делаете!
Цель здесь - вернуть TNTLoginViewController во время процесса восстановления состояния с его делегатом, установленным для его родителя.
Сначала вы должны создать объект TNTLoginViewController. Вы упомянули раскадровку, поэтому я буду загружать ее оттуда. Я предполагаю, что у вас есть довольно стандартная установка с файлом Main.storyboard, и личность правильно установлена в Identity Inspector.
TNTLoginViewController * loginViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"loginViewController"];
Далее вам нужно установить его делегат для родителя. Я собираюсь предположить, что есть UINavigationController, соединяющий эту модель. Чтобы найти это в объекте application-делегата, вам нужно покопаться в его свойстве window.
Свойство окна является объектом UIWindow, у которого есть другое свойство, называемое rootViewController. Это объект UIViewController. Так как я предполагаю, что есть UINavigationController, соединяющий вашу модель, вам нужно будет вписать этот UIViewController в UINavigationViewController (я бы разместил ссылку, которую я не могу, на моем текущем уровне репутации).
Теперь вы можете использовать свойство topViewController контроллера в верхней части стека навигации, которое вы хотите установить в качестве своего делегата! Если нет, то вы можете перемещаться по объекту UINavigationController, для которого вы хотите использовать его в качестве делегата.
И помните, поскольку вы устанавливаете делегата с уровня приложения-делегата, вам может потребоваться указать свой протокол здесь, чтобы избежать неопределенности.
Чтобы реализовать эти последние четыре шага в коде будет выглядеть примерно так.
loginViewController.delegate = (id <TNTLoginViewControllerDelegate>)((UINavigationController *) self.window.rootViewController).topViewController;
И тогда вы можете вернуть свой TNTLoginViewController с правильно установленным делегатом!
Убедитесь, что не забыли последствия использования application:viewControllerWithRestorationIdentifierPath:coder:
, Вы хотите сделать это только в случае восстановления вашего TNTLoginViewController. К счастью, вы можете проверить это с помощью переданного аргумента identifierComponents. Сравните это с вашим именем в Identity Inspector и верните nil, если они не совпадают.
Ваш последний метод в файле AppDelegate.m будет выглядеть примерно так.
- (UIViewController *)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder
{
if ([[identifierComponents lastObject] isEqualToString:@"loginViewController"]) {
TNTLoginViewController * loginViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"loginViewController"];
loginViewController.delegate = (id <TNTLoginViewControllerDelegate>)((UINavigationController *) self.window.rootViewController).topViewController;
return loginViewController;
}
return nil;
}
Надеюсь, это поможет!