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

5

我试图使用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

开始:实现

- (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的委托:即使我的呈现VC的类在其头文件中公开采用了`TNTLogingViewControllerDelegate>`协议,Xcode也不会让我绘制该连接。这可能是一个单独的问题,或者可能不被允许。 3.使用应用程序委托级别的`application:viewControllerWithRestorationIdentifierPath:coder:`返回具有其委托设置为我的呈现视图控制器的模态视图控制器。我必须能够从应用程序委托派生出那个呈现VC,但它可能有效。
目前我选择第三种方法,但如果有更好的解决方案,我会非常高兴。可能会导致类似问题的设置:
1.设置数据源,例如表视图。
1个回答

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参数来检查这一点。将其与身份检查器中的标识名称进行比较,如果不匹配,则返回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;
}

我希望这可以帮助你!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接