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

我正在尝试使用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:实现

 - (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. 将我的演示VC设置为Storyboard中我的模态VC TNTLogingViewControllerDelegate>即使当我的演示VC的类在其头部公开采用了TNTLogingViewControllerDelegate>协议时,Xcode也不会让我绘制该连接。 这可能是一个单独的问题,或者这可能是不允许的。
  3. 使用应用程序 – 委托级application:viewControllerWithRestorationIdentifierPath:coder:返回一个模态视图控制器,并将其委托设置为我的呈现视图控制器。 我必须能够从应用程序代表派生VC,但它可能工作。

我现在要用#3,但如果有更好的解决scheme,有人可以推荐,我会很高兴。

会产生类似问题的设置:

  1. 设置一个数据源,比如表格视图。

你是对的,这是可以做的应用程序与委托级application:viewControllerWithRestorationIdentifierPath:coder:但你需要小心/劈刀在你如何做到这一点!

这里的目标是在状态恢复过程中返回一个TNTLoginViewController,其代理设置为其父代。

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

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

接下来,您需要将其委托设置为父级。 我将假设有一个UINavigationController连接这个模型。 要从应用程序委托对象中find它,你将需要挖掘它的窗口属性。

window属性是一个UIWindow对象,它具有另一个名为rootViewController的属性。 这是一个UIViewController对象。 因为我假设有一个UINavigationController连接你的模型,你需要将这个UIViewController转换成一个UINavigationViewController(我将这个链接放在我当前的声望级别上)。

现在,您可以使用topViewController属性控制器在导航堆栈的顶部,这是您想要设置为您的委托! 如果没有,那么你可以导航你的UINavigationController对象作为你的委托对象。

请记住,由于您是从应用程序委托级别设置代理,因此您可能需要在此指定您的协议以避免模糊。

在代码中实现这最后四步将看起来像这样。

 loginViewController.delegate = (id <TNTLoginViewControllerDelegate>)((UINavigationController *) self.window.rootViewController).topViewController; 

然后你可以返回你的TNTLoginViewController正确的设置它的委托!

确保不要忘记使用application:viewControllerWithRestorationIdentifierPath:coder:的含义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; } 

我希望这有帮助!