在搜索有用的方式来刷新UINavigationBar
时(请参阅:How to properly refresh a UINavigationBar?),我遇到了这个问题:
这会按预期刷新UINavigationBar
,即使不是一个干净的方式:
if let navigationController = self.navigationController {
navigationController.popViewControllerAnimated(false)
navigationController.pushViewController(self, animated: false)
}
但是,这会弹出当前视图控制器,但不会推送它:
navigationController?.popViewControllerAnimated(false)
navigationController?.pushViewController(self, animated: false)
这种行为如何解释?
答案 0 :(得分:3)
可选绑定允许每次以相同的方式发生整个逻辑块。多行可选链接可能使其不清楚到底会发生什么,并且可能会受到竞争条件的影响而导致意外行为。
使用可选绑定,您将创建对刚刚解开的任何内容的新引用,通常,这是一个强大的参考。它也是一个本地参考,不会受到其他情况的突变。习惯上通常也是let
。因此它将在其整个生命周期内保持相同的价值。
考虑你的例子......但稍微调整一下。
if let navigationController = self.navigationController {
// this should always pass
assert(navigationController === self.navigationController)
navigationController.popViewControllerAnimated(false)
// this next assert may fail if `self` refers to the top VC on the nav stack
assert(navigationController === self.navigationController)
// we now add self back onto the nav stack
navigationController.pushViewController(self, animated: false)
// this should also always pass:
assert(navigationController === self.navigationController)
}
这种情况正在发生,因为当导航控制器将新的视图控制器添加到其导航堆栈(使用pushViewController)
时,它会将传入的视图控制器的navigationController
属性设置为等于它自己。并且当该视图控制器时从堆栈中弹出,它将该属性设置回nil
。
让我们看看可选链接方法,再次抛出这些断言:
let navController = navigationController
// this should always pass
assert(navController === navigationController)
// assuming navigationController does not evaluate to nil here
navigationController?.popViewControllerAnimated(false)
// this may fail if `self` is top VC on nav stack
assert(navController === navigationController)
// if above failed, it's because navigation controller will now evaluate to nil
// if so, then the following optional chain will fail and nothing will happen
navigationController?.pushViewController(self, animated: false)
// if the previous assert fail, then the previous push wasn't called
// and if the previous push wasn't called, then navigation controller is still nil
// and therefore this assert would also fail:
assert(navController === navigationController)
所以在这里,self
上的实例属性被我们自己的方法调用设置为nil
,导致可选绑定和放大器之间的行为差异。链接。
但即使我们没有通过我们自己在当前线程上的操作来改变该属性,我们仍然会遇到突然该属性正在评估nil
的问题,即使它有一个有效的值。上一行。我们可以使用多线程代码来处理这个问题,其中另一个线程可能导致我们的属性值现在评估为nil
,反之亦然。
简而言之,如果您需要确保全部或全部,则需要选择可选绑定。
答案 1 :(得分:2)
可选绑定将您绑定的内容存储在变量中。在这种情况下,它是navigationController
。
另一方面,可选链接不会将左侧的值放入变量中。它只说
我会检查问号左边的这个值是否为零。如果不是,请评估表达式的其余部分。如果是,则评估为nil
因此,在弹出视图控制器(第一行)后,self.navigationController
变为nil,因此不会评估第二行中的方法调用。
您可能会遇到以下困惑:
为什么
self.navigationController
变为零?
一种可能性是self
是navigationController
的顶级视图控制器。弹出self
后,它不属于任何导航控制器。
为什么可选绑定工作但不是可选链接?
正如我之前所说,可选绑定将self.navigationController
的值放入变量navigationController
。因此,即使self.navigationController
为零,navigationController
仍保持其值。