使用GCD和NSNotificationCenter时,在显示控制器之前出现长时间延迟

时间:2015-04-27 17:13:05

标签: ios uiviewcontroller uinavigationcontroller nsnotificationcenter

奇怪的行为让我无法理解 - 当我将第二个视图控制器推到UINavigationController上时,在新视图出现之前有5-10秒的延迟。正在根据NSNotificationCenter通知推送第二个视图控制器。

奇怪:延迟只发生在从后台线程而不是主线程发布事件时(参见下面示例代码中的注释)。

为什么会出现这种延迟?这在模拟器和设备上都会发生。

这是控制台输出。如您所见,所有日志都会及时显示,而不是第二个视图控制器,它在大约5-10秒后突然出现。

2015-04-27 06:58:47.973 DelayedViews[49845:5005806] Background thread started
2015-04-27 06:58:49.978 DelayedViews[49845:5005806] Pushing second view controller
2015-04-27 06:58:49.979 DelayedViews[49845:5005806] Done pushing second view controller
2015-04-27 06:58:49.980 DelayedViews[49845:5005806] In completion block
2015-04-27 06:58:49.980 DelayedViews[49845:5005783] Back on main thread

这是我的简单示例AppDelegate.m,它演示了这个问题。

#import "AppDelegate.h"

@interface AppDelegate ()
@property (nonatomic, strong) UINavigationController *navController;

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];

    self.navController = [[UINavigationController alloc] init];
    self.window.rootViewController = self.navController;

    UIViewController *vc = self.viewControllerOne;
    [self.navController pushViewController:vc animated:YES];

    // register for notification center
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pushSecondViewController) name:@"PushSecondVC" object:nil];

    // start background thread that posts notification and calls completion block

    void (^completion)() = ^void() {
        NSLog(@"In completion block");
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Back on main thread");
                // If I do the notification here, the 2nd view controller is pushed immediately
                // [[NSNotificationCenter defaultCenter] postNotificationName:@"PushSecondVC" object:self];
        });
    };

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSLog(@"Background thread started");
        [NSThread sleepForTimeInterval:2]; // simulate some work

        // if the notification is posted here, there is a 5-10 second delay on simulator before second VC appears
        // even though the 2nd VC was pushed onto navigationcontroller.
        [[NSNotificationCenter defaultCenter] postNotificationName:@"PushSecondVC" object:self];

        // call completion block now
        completion();
    });


    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    return YES;
}

- (UIViewController*)viewControllerOne {
    UIViewController *vc = [[UIViewController alloc] init];
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(8, 100, 100, 100)];
    label.text = @"View #1";
    [vc.view addSubview:label];
    return vc;
}

- (UIViewController*)viewControllerTwo {
    UIViewController *vc = [[UIViewController alloc] init];
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, 200, 100, 100)];
    label.text = @"View #2";
    [vc.view addSubview:label];
    return vc;
}

- (void)pushSecondViewController {
    NSLog(@"Pushing second view controller");
    UIViewController *vc = self.viewControllerTwo;
    [self.navController pushViewController:vc animated:YES];
    NSLog(@"Done pushing second view controller");
}

@end

1 个答案:

答案 0 :(得分:1)

谢谢,A-Live,似乎是它。

我将pushSecondViewController更改为以下内容,现在看起来效果很好。我想知道幕后发生了什么以及为什么这个观点出现需要这么长时间?

- (void)pushSecondViewController {
    if (![[NSThread currentThread] isMainThread]) {
        dispatch_sync(dispatch_get_main_queue(), ^{
            [self pushSecondViewController];
        });
        return;
    }

    NSLog(@"Pushing second view controller");
    UIViewController *vc = self.viewControllerTwo;
    [self.navController pushViewController:vc animated:NO];
    NSLog(@"Done pushing second view controller");
}