【问题标题】:viewDidAppear: called when using presentViewController:animated:completion:viewDidAppear: 使用 presentViewController 时调用:animated:completion:
【发布时间】:2013-05-27 03:10:29
【问题描述】:

我有一个视图控制器,它可以查询网络服务是否应该显示插页式广告。如果是这样,则使用 presentViewController:animated:completion: 实例化和呈现另一个视图控制器。根据this answerdocs,我假设 viewDidAppear: 在关闭呈现的视图控制器(它自己完成)时不会被调用。从概念上讲,无论如何对我来说,呈现视图控制器的视图永远不会从视图层次结构中删除,因此永远不需要“重新出现”。我显然错了。那么发生了什么?为什么我看到的与文档所说的不同?

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [[AdService sharedAdService] adForSlotName:@"Main Interstitial" completionBlock:^(Ad *adForSlotName) {

        if(adForSlotName)
        {
            InterstitialAdViewController_iPhone *interstitialAdViewController = [[InterstitialAdViewController_iPhone alloc] init];
            interstitialAdViewController.ad = adForSlotName;

            dispatch_queue_t mainQueue = dispatch_get_main_queue();
            dispatch_async(mainQueue, ^{

                [self presentViewController:interstitialAdViewController animated:YES completion:^{}];

            });

            [interstitialAdViewController release];
        }
    }];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [[AdService sharedAdService] clearAdForSlotName:@"Main Interstitial"];

    [super viewWillDisappear:animated];
}

【问题讨论】:

  • 哪个视图在什么时候收到 viewDidAppear?对我来说,你的问题似乎不清楚。我假设只要出现视图就会调用 viewDidAppear 。出现可能是在呈现视图后发生的事情,但也可能在之前覆盖它的视图被移除(关闭)后发生在底层视图上。
  • 抱歉,viewDidAppear: 在呈现的视图控制器上被调用,只要呈现的视图控制器关闭。
  • 这将符合我在第一条评论第二部分中起草的期望,并且完全符合预期。
  • 谢谢,直到,我在下面的评论中提到我的问题始于 viewWillDisappear: 但我认为我可以用 viewDidAppear: 来构建我的问题。也许我认为 viewDidAppear: 被称为视图必须已经“消失”或从未出现过。

标签: ios objective-c uiviewcontroller grand-central-dispatch uiview-hierarchy


【解决方案1】:

您链接的答案是关于 viewDidDisappear 的行为,而不是 viewDidAppear。您链接的文档中的注释说,当子视图控制器以弹出框呈现被关闭时,不会在呈现视图控制器上调用 viewDidAppear。

在您的情况下,您正在呈现没有弹出窗口的子视图控制器,所以我阅读了文档的注释(以“证明规则的例外”的方式)说 viewDidAppear 应该在子视图控制器上调用在您的情况下,视图控制器被解雇了。

我认为当子视图控制器出现时,您应该看到在父视图控制器上调用 viewDidDisappear。我在一个最小的测试应用程序中尝试了这个,使用这个代码来展示一个子视图控制器:

Parent *parent = [[Parent alloc] initWithNibName:nil bundle:nil];
[self.window setRootViewController:parent];
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    Child *child = [[Child alloc] initWithNibName:nil bundle:nil];
    [parent presentViewController:child animated:YES completion:^{
        NSLog(@"Child presented");
        double delayInSeconds = 2.0;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [parent dismissViewControllerAnimated:YES completion:^{
                NSLog(@"Child dismissed");
            }];
        });
    }];
});

并且,在 Parent 和 Child 类中记录对各种外观相关回调的调用。这是我看到的顺序:

使父视图控制器成为根视图控制器:

Parent viewWillAppear:
Parent viewDidAppear:

呈现子视图控制器:

Parent viewWillDisappear:
Child viewWillAppear:
Child viewDidAppear:
Parent viewDidDisappear:
Child presented

关闭子视图控制器:

Child viewWillDisappear:
Parent viewWillAppear:
Parent viewDidAppear:
Child viewDidDisappear:
Child dismissed

所以这对我来说似乎在内部是一致的——当子视图控制器出现时,父级会收到消失调用,而当子视图控制器被关闭时会调用外观。这仍然与 viewWillAppear 的记录行为一致,因为我没有向子视图控制器显示弹出框。

恐怕我不知道为什么当您的子视图控制器出现时您没有收到 viewWill/DidDisappear 调用。

【讨论】:

  • 事实上,我的问题始于 viewWillDisappear:在呈现视图控制器时被调用,但我认为这更多是其他事情的症状。所以我从我的观点WillAppear 的角度提出了这个问题。也许我应该重写整个问题。谢谢。
  • 嗨亚伦,还有一条评论。对我来说,如果预期的行为是在呈现视图控制器时不调用 viewDidDisappear ,那么原始视图控制器也不应该在关闭呈现的视图控制器时调用 viewWillAppear ,这似乎很奇怪。你同意吗?
  • 我同意这看起来很奇怪,事实上,当我尝试这个时,我得到了 viewDidDisappear 调用来呈现子视图控制器(请参阅我的编辑)。
  • 这太棒了,谢谢。这个问题与我对文档的解释和其他问题有关。
  • @rob5408 你可能在这里迷失了我,但我觉得可能值得注意的是,外观回调经常被不一致地调用实际上与有缺陷的视图控制器层次结构有关。当人们试图在旧的 iOS 版本上重新发明视图控制器包含时,我已经看到了很多这样的事情发生。另请注意,出现回调的顺序是特定于 iOS 版本的,并未准确记录。
【解决方案2】:

我也经历过同样的行为。 viewDidAppear: 方法在关闭呈现的视图控制器时被调用。但是,有一条出路。在控制器中创建一个布尔变量,在viewDidLoad 中将其设置为NO,并在viewDidAppear: 中检查它。然后将其设置为YES。像这样:

#import "MyViewController.h"

@implementation MyViewController {
    BOOL alreadyShown;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    alreadyShown = NO;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (!alreadyShown) {
        alreadyShown = YES;
        //do your stuff
    }
}

@end

【讨论】:

  • 谢谢亚当,我将使用这种方法来获得我正在寻找的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-26
  • 2016-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多