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

Posted

技术标签:

【中文标题】具有自定义委托或数据源的视图控制器的状态保留【英文标题】:State Preservation for View Controllers with Custom Delegates or Data Sources 【发布时间】:2014-01-12 23:55:42 【问题描述】:

我正在尝试使用 ios 6+(我的应用程序是 7.0+)状态保留来保留从另一个视图控制器模态呈现的视图。因此,它具有典型的模态视图控制器解除模式:

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: 并不能帮助我指向我的特定呈现视图控制器。 在 Storyboard 中将我的演示 VC 设置为我的模态 VC 的委托:Xcode 不允许我绘制该连接,即使我的演示 VC 的类在其标题中公开采用 TNTLogingViewControllerDelegate&gt; 协议。这可能是一个单独的问题,也可能是不允许的。 使用 application-delegate-level application:viewControllerWithRestorationIdentifierPath:coder: 将模态视图控制器及其委托设置返回给我的呈现视图控制器。我必须能够从 App Delegate 派生出展示的 VC,但它可能会起作用。

我现在选择#3,但如果有人可以推荐更好的解决方案,我会很高兴。

会产生类似问题的设置:

    设置数据源,比如表格视图。

【问题讨论】:

【参考方案1】:

您是对的,这可以通过 application:viewControllerWithRestorationIdentifierPath:coder: 从应用程序代理级别执行,但您需要小心/谨慎地执行此操作!

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

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

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

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

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;

我希望这会有所帮助!

【讨论】:

以上是关于具有自定义委托或数据源的视图控制器的状态保留的主要内容,如果未能解决你的问题,请参考以下文章

自定义委托方法触发正常,但值不会保留在其他方法中

从 nib 文件在自定义视图中设置自定义委托

如何附加滚动视图委托方法?

在具有委托的视图控制器之间传递多个值

在自定义 UIview 中设置 UItableview 的委托和数据源

是否需要保留数据源的控制器和 uiPickerview 的委托?