【问题标题】:UIViewController dismiss few controllers (iOS 4.3 and higher)UIViewController 关闭少数控制器(iOS 4.3 及更高版本)
【发布时间】:2013-03-27 09:39:16
【问题描述】:

我有使用 presentModalViewController 方法呈现的 UIViewController 层次结构。

我有一个单例,可以将所有呈现的视图控制器抓取到一个数组中。

例如,我展示了控制器 A,然后是 B,然后是 C。我将每个控制器插入到索引 0。

所以我的层次结构如下

C

B

一个

这是我的单身

@implementation PresentHelper

- (id)init
{
    self = [super init];
    if (self) {
        self.viewControllers = [NSMutableArray new];
    }
    return self;
}

+ (PresentHelper *)sharedInstance
{
    static dispatch_once_t pred;
    static PresentHelper *sharedInstance = nil;
    dispatch_once(&pred, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void)backToViewControllerA
{
    for (UIViewController *controller in self.viewControllers) {
        [controller dismissModalViewControllerAnimated:NO];
    }
    [self.viewControllers removeAllObjects];
}

@end

UIViewController C 中我调用backToViewControllerA 方法。

所以当我调试这个方法时,我想知道为什么- viewDidLoad 方法(对于 self.viewControllers 中的每个控制器)在这一行之后调用[controller dismissModalViewControllerAnimated:NO];,因为我认为它不应该像这样工作,但它可以工作。

所以,也许这不是返回视图控制器 A 的一种方法,但无论如何我的问题都与 viewDidLoad 方法有关。

这也是我如何展示每个控制器的代码。我有基类,每个(A、B、C 控制器都继承自它)。

- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated
{
    PresentHelper *presentHelper = [PresentHelper sharedInstance];
    [presentHelper.viewControllers insertObject:modalViewController atIndex:0];
    [super presentModalViewController:modalViewController animated:animated];
}

也收到了这条消息

NSArray 在枚举时发生了变异

所以我认为解雇后我失去了我的对象,也许这是我的问题。

【问题讨论】:

  • 那么...您是对 viewDidLoad 行为有疑问,还是在问从 C 到 A 的最佳方式是什么?单例的全部原因是否只是为了方便从 C 导航回 A?解决方案是否需要兼容iOS4.3?
  • 问题是关于最好的方法。我发现了奇怪的行为,这与我的数组发生了变异,并且我认为未连接到 viewDidLoad。谢谢
  • 需要在iOS4.3上运行吗?这是关于可能的解决方案的一个重要区别。
  • 是的,它必须适用于 4.3 版本

标签: ios uiviewcontroller presentmodalviewcontroller


【解决方案1】:

这似乎不太适合单例。

您可以通过多种方式返回 A。您不需要构造额外的委托方法或属性,因为每个控制器都通过其 presentingViewController 属性引用前一个控制器。 (我会改写...对于 iOS5+,您可以使用内置的 viewController 属性presentingViewController)。为了与 iOS4.3 保持兼容,请创建一个属性并将其放入您的基类 @interface

    @property (nonatomic, assign) UIViewController* presentingController;

同样在你的基类接口中,声明一个方法:

    - (void) dismissBackToA;

@implementation@synthesize 你的属性中定义dismissBackToA

 - (void) dismissBackToA
{
    if ([[self presentingController] respondsToSelector:@selector(dismissBackToA)]) {
           [[self presentingController] performSelector:@selector(dismissBackToA)];
    }
}

在您的模态呈现代码中,在呈现的 VC 中设置对 self 的引用 - 例如:

   MasterViewController* BViewController = [[BViewController alloc] init];
   BViewController.presentingController = self;
   [self presentModalViewController:BViewController animated:YES];

现在您所要做的就是在您的 AViewController 子类中覆盖 dismissBackToA

- (void) dismissBackToA
{
    [self dismissModalViewControllerAnimated:YES];

}

这将允许您以菊花链方式连接任意数量的模态视图控制器...通用 dismissBackToA 会将链“展开”回 A。A 的覆盖方法将解除它的模态 (B)。这应该清除链中的所有其他控制器。 presentController 几乎充当标准代表 - 我已经过度指定它以强调它与 iOS5+ 中的 presentingViewController 相似。我对非Arc内存有点生疏,但我认为需要分配而不是保留。

恐怕我无法 100% 测试,因为我手头没有 iOS4.3 模拟器...

更新

您也可以在链上一直传递对 A 的引用,并在需要时发送[self.referenceToA dismissModalViewControllerAnimated:YES],但这种方式感觉更通用一些。

您还应该注意 presentModalViewController:animated:dismissModalViewControllerAnimated: 在 6.0 中已弃用:现在您应该使用

- presentViewController:animated:completion: 
- dismissViewControllerAnimated:completion:

在 5.0 中引入。

它们仍然有效,但请将此视为警告 - 您必须准备好放弃对 4.3 的支持,或者让您的代码在未来以操作系统版本为条件。

【讨论】:

  • 我不确定我是否明白你的意思。我有用于 A、B 和 C 视图控制器的 BaseViewController(A:BaseViewController、B:BaseViewController 和 C:BaseViewController)。当我点击 Home 按钮时,我需要关闭控制器 C 和 B。我已经在基本视图控制器中实现了你的代码,但也许我们谈论不同的事情。
  • 我知道了 =) 我只需要调用 [super dismissBackToA] 而不是 [self dismissBackToA]
  • @MatrosovAlexander - 检查我更新的答案,您需要在将来使用已弃用的方法时小心...
【解决方案2】:

这不是关闭控制器的好方法。仅仅为此目的创建一个单例似乎是个坏主意。到目前为止,最简单的方法是在情节提要中使用 unwind segue 来完成,但我认为这仅适用于 iOS 6(也许 iOS 5 也是如此)。如果您想在代码中执行此操作,那么您应该使用委托或 NSNotifications 让 A 解除 C(这也将解除 B)。此外,如果您要在代码中呈现模态视图控制器,则不应使用这种已弃用的方法,而应使用 presentViewController:animated:completion:。

修改后:

你也可以从控制器 C 中这样做:

[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];

【讨论】:

  • OP 指定 iOS4.3 及更高版本...因此不允许使用 Storyboard 或展开转场。
  • @MatrosovAlexander,是的,我刚刚注意到并编辑了我的答案。
  • 委托呢。例如,在 C 控制器中关闭 B 中的调用委托方法后,并一一关闭它们
  • @MatrosovAlexander,如果需要,您可以一个一个地解除它们,或者将 A 的引用传递给 B,然后传递给 C,这样您就可以从 A 发出解除调用,这将解除 A 之后的任何控制器. 或者像我上次使用presentingViewController编辑一样。
猜你喜欢
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-06
相关资源
最近更新 更多