2017-01-04 20 views
1

UIStoryboardのinstantiateViewController(withIdentifier:)メソッドを使用してビューコントローラをインスタンス化した後にキーワードを使用してダウンキャストする必要があるのはなぜですか? UIStoryboardメソッドinstantiateViewController(withIdentifier:)はすでにUIViewControllerを返しており、ストーリーボードIDに基づいてどのクラスを使用しているかを知っています。SwiftのinstantiateViewController(withIdentifier :)の後にダウンキャストが必要な理由

次のコードは機能し、コンパイルされますが、その理由を理解したいと思います。私がドキュメンテーションに基づいてこれを構築していたのであれば、ダウンキャスティングが必要であるとは考えていなかったので、関数から返される型および/またはオブジェクトに関して私が学習しなかった部分を理解しようとしています。

func test_TableViewIsNotNilOnViewDidLoad() { 

     let storyboard = UIStoryboard(name: "Main", bundle: nil) 

     let viewController = storyboard.instantiateViewController(
      withIdentifier: "ItemListViewController") 

     let sut = viewController as! ItemListViewController 

     _ = sut.view 

     XCTAssertNotNil(sut.tableView) 

    } 
+3

'withIdentifier:" ItemListViewController "はストーリーボード内のView ControllerのIDを参照し、' UIViewController'クラス型を返します。それに関連付けられた 'UIViewController'クラスは返されません。 Down-castingによってClassを割り当てます。 –

+2

宣言だけを読んでください! 'func instantiateViewController(識別子付き:識別子付き) - > UIViewController'かなり簡単です。 – matt

答えて

3

storyboard.instantiateViewController...はいつものUIViewController(特定のサブクラスの基本クラスを)返しますので、あなたのサブクラスに固有の実装の詳細を知ることができないので。

上記のメソッドは、ストーリーボードIDに基づいてサブクラスタイプを推論しません。これは、ダウンキャスト時にコード内で行うことです(here参照)。

func instantiateViewController(withIdentifier identifier: String) -> UIViewController 

あなたは上記の方法からUIViewControllerを取得し、あなたは(あなたがUIViewControllerサブクラスとしてItemListViewControllerを定義したので、それは常に動作します)あなたのItemListViewControllerにそれをダウンキャスト強制ので、だから、それが動作します。

PS。私はあなたの質問を理解したとは確信していませんが、これはかなり簡単です。

+0

"この識別子はビューコントローラオブジェクト自身のプロパティではなく、ストーリーボードファイルだけがビューコントローラの位置を特定するために使用されています"という誤った解釈をしています。さて、私は学んでいる、大いに感謝して、私は前進できる。 –

1

これは完全に間違っているストーリーボードIDに基づいて、どのクラス

を知っています。ストーリーボードIDは文字列です。あなたの場合は、静的な文字列になることがありますが、このメソッドはそれを必要としません。それは実行時に計算することができます(私は個人的にそれを行うコードを書いています)。あなたの文字列はクラス名と一致しますが、これが本当である必要はありません。識別子は、どの文字列でもかまいません。そして、ストーリーボードは編集プロセスの一部ではありません。ストーリーボードは、コードがコンパイルされてから実行されるまでの間に、問題のオブジェクトが異なるタイプになるように簡単に変更できます。

コンパイル時にクラスを計算するのに十分な情報がないため、コンパイラは、それがうまくいくことを明示的に約束し、失敗した場合の対処方法を決定する必要があります。 as!を使用しているため、「間違っているとクラッシュしてください」と言います。

+0

私はこれを好きです。オプションを使用すると、エラーやアプリのクラッシュを避けるために残念なことよりも安全な方法のようです。大いに義務付けされた –

1

オブジェクト指向プログラミングに関する一般的な背景説明を読んで理解してください。主な概念は、クラス、インスタンス/オブジェクト、継承、多型です。

storyboard.instantiateViewController()ItemListViewControllerのインスタンスを作成しますが、UIViewControllerとして返されます。この部分を理解することが難しい場合、これは客観的な知識ベースが必要な場所です。 オブジェクト指向言語(OO languges)では、例えばC++のように、クラス(インスタンスとも呼ばれます)のインスタンスは、その親(または祖父母や偉大な親など)クラスへのポインタによって参照できます。オブジェクト指向に関する大部分の文献やチュートリアルでは、継承やキャスト、ポリモーフィズムに関する概念は、基本クラスや派生オブジェクトなどへのポインタを使用して常に説明されています。 しかし、スウィフトでは、他の多くのオブジェクト指向言語のようにポインタが公開されていません。あなたのコードで

、そしてそれはOOで最もチュートリアルは、物事を説明する方法であるとして、それはC++または類似のオブジェクト指向言語だったかのように単純化された方法とでこれを説明する:

let viewController = storyboard.instantiateViewController(
      withIdentifier: "ItemListViewController") 

viewControllerは "タイプItemListViewControllerのオブジェクトを指しているクラスタイプUIViewControllerの「ポインタ」を含む。

コンパイラは、UIViewControllerというポインタであることを認識しています。したがって、明示的にキャストを行い、それらを知ることができない限り、具体的なメソッドまたはプロパティについてはわかりません。ItemListViewController

+0

クラスの継承がどのように使用され、AppleのAPIに関して使用されているかを理解するために、私の目を100倍以上開いた方がいいです。かなり義務付けられた –

1

これは部分的には多型性によるものです。あなたがPersonStudentのいずれかを取得しますtagパラメータの値に応じて

class Person { 
    let name: String 
} 

class Student: Person { 
    let schoolName: String 
} 

func createRandomPerson(tag: Int) -> Person { 
    if tag == 1 { return Person() } 
    else { return Student() } 
} 

let p = createRandomPerson(2) 

:たとえば、次のコードを取ります。あなたが関数に2を渡した場合

さて、あなたはcreateRandomPersonStudentインスタンスを返すことを確認することができますが、あなたはまだcreateRandomPersonは、基本クラスのインスタンスを返しますシナリオがあるとダウンキャストする必要があります。

正しい識別子を渡した場合、期待通りのビューコントローラが得られることがわかりますが、ストーリーボードでは実質的にUIViewControllerサブクラス(またはさらにUIViewController)のインスタンスが作成できるため、戻り値の型はUIViewControllerに設定されています。

同様に、数値計算が間違っている場合、つまり1createRandomPerson()に渡すか、またはストーリーボードに間違った識別子を渡した場合、予想どおりに受け取られません。

+0

は正当なようです。たとえば、私がダウンキャスティングプロセスをやっていないとしましょう。変数のトラブルシューティングに使用できるプロセスの名前や方法がありますか?そのタイプがわかりにくい場合は、そのタイプを確認してください。たぶん、コンソールはどのタイプのトラブルシューティングのために吐き出されているのでしょうか? –

+1

'is'演算子で' viewController is MyViewController'、 'if-let'で確認できます:' let castedController = viewController as? MyViewController {良いコントローラ} else {悪いコントローラ} ' – Cristik

関連する問題