具有自定义代理或数据源的视图控制器的状态保留

时间:2014-01-12 23:55:42

标签: ios objective-c delegates uikit-state-preservation

我正在尝试使用iOS 6+(我的应用程序是7.0+)State Preservation来保留从另一个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:implementation

- (IBAction)getStarted:(id)sender
{
    // Perform login
    ...

    // Dismiss me
    [self.delegate TNTLoginViewControllerDismiss:self];
}

TNTLoginViewControllerDismiss:委托上的方法,它提供了模态

- (void)TNTLoginViewControllerDismiss:(TNTLoginViewController *)controller
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

这一切都像魅力一样!直到国家保护。简单地说,我不知道TNTLoginViewController如何保留其委托。我理解为什么它不能:它只是一个指针!所以我尝试了各种派生委托的方法:

  1. 恢复课:遗憾的是,作为一种课堂方法,viewControllerWithRestorationIdentifierPath:coder:并没有帮助我指出我特定的视觉控制器。
  2. 在Storyboard中将我的演示VC设置为模态VC的委托:Xcode不会让我绘制该连接,即使我的演示VC的类在其标题中公开采用了TNTLogingViewControllerDelegate>协议。这可能是一个单独的问题,或者可能不允许这样做。
  3. 使用application-delegate-level application:viewControllerWithRestorationIdentifierPath:coder:返回一个模态视图控制器,其委托设置为我呈现的View Controller。我必须能够从App Delegate派生出VC,但它可能有效。
  4. 我现在正在使用#3,但如果有更好的解决方案有人可以推荐,我会很激动。

    会产生类似问题的设置:

    1. 设置数据源,例如表格视图。

1 个答案:

答案 0 :(得分:1)

你是对的,这可以通过application:viewControllerWithRestorationIdentifierPath:coder:从应用程序委托级别开始,但是你需要小心/切割你如何做到这一点!

此处的目标是在状态恢复过程中返回TNTLoginViewController,并将其委托设置为其父级。

首先,您必须创建一个TNTLoginViewController对象。你提到了一个故事板,所以我将从那里加载它。我将假设您使用Main.storyboard文件进行了相当标准的设置,并在Identity Inspector中正确设置了身份。

TNTLoginViewController * loginViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"loginViewController"];

接下来,您需要将其委托设置为父级。我将假设有一个连接此模型的UINavigationController。要从application-delegate对象中找到它,您需要深入了解它的窗口属性。

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

我希望这有帮助!