尽管UI操作在主线程上运行,但UI仍然出现故障

时间:2016-04-25 18:49:54

标签: swift uikit nsthread

我有一个错误(我已经第二次见面了)在我们的项目中,我只是在UIViewController视图的顶部添加一个视图。没什么了不起的,像这样:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    self.displayEmailNotificationsIfNeeded()
}

该错误是由于某种原因,自动布局工作不正确,并没有将其添加到顶部,但比所需要的低60pt。我怀疑~60pt来自手动顶部约束调整,包括导航栏和状态栏,但这并不重要。

事实是,如果我在主队列上显式运行方法,问题就会消失,如下所示:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    print("is main thread: ", NSThread.isMainThread())
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        print("is main thread inside block: ", NSThread.isMainThread())
        self.displayEmailNotificationsIfNeeded()
    })
}

两种情况下,打印语句都会返回true。这不是很糟糕,但出于好奇,我想了解是什么导致了这一点。有没有办法调试这种情况,并理解为什么在主线程上显式执行操作修复了一些UI故障?

3 个答案:

答案 0 :(得分:1)

一个有根据的猜测 - 并不是displayEmailNotificationsIfNeeded无法在主线程上运行而不是明确地将其添加到队列中,这更多的是时间问题。由于故事板中的其他约束可能会在viewDidAppear完成执行后处于不同状态时移动元素。在执行代码之前,异步添加执行块允许viewDidAppear完成(以及在主队列上同步运行的任何其他内容)。

希望这有帮助。

答案 1 :(得分:0)

这不是一个肯定的答案,因为我需要重现这个错误,但这是我认为可能会发生的事情。

当你直接执行代码时,布局还没有完全准备好(这取决于你可能拥有的其他代码),因此布局错误。当您在dispatch_async中显式运行代码时,您也在主线程上运行它,但是在稍后的某个时间点,直到布局准备好并且您看到正确的结果。

此外,执行此代码,您应该能够理解。

    print("1");
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        print("2");
    })
    print("3");

答案 2 :(得分:0)

尝试在viewWillLayoutSubviews()中运行它。此时,您的视图控制器.view应该完全布局。请注意,此方法可能会被多次调用(例如:如果.view调整大小)。