2016-08-21 11 views
2

リフレッシュするproperyの方法を探している間UINavigationBar(参照:How to properly refresh a UINavigationBar?)を、私はこの質問に出くわした:これは、更新さオプションのチェーンとオプションのバインディング:いつ使用するか?

UINavigationBar意図したように、たとえないクリーンな方法で:しかし

if let navigationController = self.navigationController { 
    navigationController.popViewControllerAnimated(false) 
    navigationController.pushViewController(self, animated: false) 
} 

現在のView Controllerはポップアップしませんが、それをプッシュしません:

navigationController?.popViewControllerAnimated(false) 
navigationController?.pushViewController(self, animated: false) 

どのようにこの動作を説明できますか?

+0

ナビゲーションコントローラーが存在しないこの特定のコントローラーには何らかの状況がありますか?このプロパティはオプションですが、ナビゲーションコントローラ(Interface Builder)が常に存在する場合は、安全に展開できます。 – vadian

答えて

2

オプションのバインディングは、バインドするものを変数に格納します。この場合、それはnavigationControllerです。

一方、オプションの連鎖では、左の値を変数に代入しません。それだけです。

疑問符の左側にあるこの値がnilであるかどうかを確認します。そうでない場合は、残りの式を評価します。それがある場合は、ビューコントローラ(最初の行)、self.navigationControllerがゼロになり、2行目のメソッド呼び出しは、したがって評価されないのポップので、後はnil

に評価されます。

あなたはこれらの混乱があるかもしれません:

self.navigationControllerがnilになるのはなぜ?

selfは、navigationControllerのトップビューコントローラです。 selfがポップされた後は、どのナビゲーションコントローラにも属しません。

オプションバインドは機能しますが、オプションのチェーンはできません。

これまで説明したように、オプションのバインドでは、self.navigationControllerという値が変数navigationControllerに格納されます。したがって、self.navigationControllerがnilであっても、navigationControllerはその値を維持します。

2

オプションのバインディングを使用すると、ロジックのブロック全体を常に同じ方法で実行できます。オプションの連鎖を複数回実行すると、何が起こるのかが不明確になる可能性があり、予期しない動作を引き起こす競合条件の影響を受ける可能性があります。

オプションのバインドを使用すると、アンラッピングしたものに新しい参照を作成することになります。これは一般的に強力な参照です。それはまた、他の症例から突然変異の影響を受けない地方の参考文献です。習慣によっても一般的にletです。したがって、それは生涯を通じて同じ価値を保持します。

あなたの例を考えてみましょう...しかし少し微調整してください。

これは、ナビゲーションコントローラは、 pushViewController)で(そのナビゲーションスタックに新しいビューコントローラを追加するためとして、それ自体に等しいビューコントローラの navigationControllerプロパティに渡さセット起こっている。そして、そのビューコントローラがオフにポップされたときに
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) 
} 

積み重ね、それが戻っ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) 

だからここに、私たちのINSTA selfのnceプロパティが、nilに設定されています。これは、独自のメソッド呼び出しによって、オプションのバインディング&チェーニングの間の動作の違いを引き起こします。

しかし、現在のスレッドで独自のアクションでそのプロパティに変更を加えていない場合でも、前の行に有効な値を持っていても突然プロパティがnilに評価されています。これをマルチスレッドコードで実行すると、値がnil、またはその逆の値を持つプロパティが別のスレッドによって発生する可能性があります。

要するに、すべてまたはなしを確認する必要がある場合は、オプションバインディングを優先する必要があります。

関連する問題