29668


以下のようにメソッド外でクラスをインスタンス化しておきます。

[code]

    var firstCtrl = firstViewController()
    
[/code]

その後以下のif文で箇所で`firstViewController()`クラスの`viewDidLoad`が呼ばれました。

[code]

    for subv in self.mainContainer.subviews {
    
        if subv == self.firstCtrl.view {  
            subv.removeFromSuperview()
        }
    }
    
[/code]

インスタンス化してからこの箇所で初めて`firstCtrl`を使い、`viewDidLoad`が呼ばれたのでSwiftではインスタンス化してから初めて使う場合は`viewDidLoad`が呼ばれるようになったのかと思ったのですがどうなのでしょうか？

Objective-Cでも試してみましたが呼ばれず、他の言語では一般的な動きだったりするという情報を見たのでそうなのかと思いました。


CC BY-SA 3.0
2016-10-18T09:54:19.620
29663
2016-10-18T12:47:46.647
14782
question
swift xcode swift3
SwiftでviewDidLoadの呼ばれるタイミング


まず大前提ですが、`viewDidLoad()`が呼ばれるタイミングは言語によって変化することはありません。このメソッドはSwiftやObjective-
Cなどの言語機能の一部として呼ばれるのではなく、iOSのViewControllerのライフサイクル管理の一部として呼ばれます。内部的には`viewDidLoad`と言うセレクタで表されるメソッドを呼び出しているだけです。

_Objective-Cでも試してみましたが呼ばれず_ とありますが、こちらで同じ動作をするコードをObjective-
Cで記述してみましたが、`viewDidLoad`が呼ばれるのは確認できました。おそらくあなたが試されたコードはSwift版と全く同じ動作にはなっていなかっただけだろうと思います。

で、実際に`viewDidLoad()`がいつ呼ばれるのかについては、Appleの公式リファレンス等を参考にしてください。

[viewDidLoad()](https://developer.apple.com/reference/uikit/uiviewcontroller/1621495-viewdidload)

> This method is called after the view controller has loaded its view  
>  hierarchy into memory. This method is called regardless of whether the  
>  view hierarchy was loaded from a nib file or created programmatically  
>  in the loadView() method.
>
> このメソッドはview
> controllerがそのview階層を全てメモリ中に読み込んだ後に呼び出されます。view階層がnibファイルからロードされたか`loadView()`メソッドの中でプログラム的に生成されたかには関係ありません。

あなたのコードの場合、nibファイルからロードされたのでないことは間違いありませんから、`loadView()`が呼ばれてその中でview階層が作成されてメモリ中に読み込まれたから`viewDidLoad()`が呼ばれたのだ、と言うことになります。

では、どこにも記述のない`loadView()`がどこで呼び出されたのか、ですが、`view`プロパティの方にこんな記述があります。

[view](https://developer.apple.com/reference/uikit/uiviewcontroller/1621460-view)

> If you access this property and its value is currently `nil`, the view  
>  controller automatically calls the `loadView()` method and returns the  
>  resulting view.
>
> このプロパティをアクセスする時に、その値が`nil`であればview  
>  controllerは自動的に`loadView()`メソッドを呼び出し、その結果のviewを返します。

つまり、 _インスタンス化してから初めて使う場合はviewDidLoadが呼ばれる_
のではなく、`view`プロパティが`nil`の状態で`view`プロパティを参照しようとすると、`loadView()`が呼ばれ、その結果として`viewDidLoad()`も呼ばれる、と言うことになります。

_他の言語では一般的な動きだったりするという情報_ がどのような情報を見られたのかわからないのですが、この動作はSwiftでもObjective-
Cでも同じです。時間が取れましたらObjective-Cのコードが完全にSwiftと同じになるようにして試して見られたらどうかと思います。


CC BY-SA 3.0
2016-10-18T11:53:09.060
29668
2016-10-18T12:47:46.647
2020-06-17T08:14:45.997
-1
13972
29663
answer


`viewDidLoad()`メソッドがいつ呼ばれるかというと、`UIViewController`のビューが、画面に表示された時です。  
検証用のコードを用意しました。

_ViewController.swift_

[code]

    import UIKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
        }
    
        // FirstViewControllerのインスタンスを生成して、それをモーダル表示する。
        @IBAction func instantiateA(_ sender: AnyObject) {
            let viewController = FirstViewController()
            present(viewController, animated: true, completion: nil)
        }
    
        // FirstViewControllerのインスタンスを生成だけして、ほかはなにもしない。
        @IBAction func instantiateB(_ sender: AnyObject) {
            _ = FirstViewController()
        }
    }
    
[/code]

ボタンをふたつ作って、`instantiateA()`と`instantiateB()`とコネクトします。

_FirstViewController.swift_

[code]

    import UIKit
    
    class FirstViewController: UIViewController {
    
        override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
            // FirstViewControllerのインスタンスが生成されたら、呼ぶ。
            print("FirstViewController was instantiated")
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // 画面に表示されたら呼ぶ。
            print("FirstViewController's view did load.")
        }
    
        // 画面をタップして、モーダル表示を終了する。
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            dismiss(animated: true, completion: nil)
        }
    
    }
    
[/code]

`instantiateA()`の出力：

> FirstViewController was instantiated  
>  FirstViewController's view did load.

`instantiateB()`の出力：

> FirstViewController was instantiated

画面に表示して、はじめて`viewDidLoad()`が呼ばれることがわかると思います。

※画面表示せずに`viewDidLoad()`を呼ぶ方法は、実用的な意味を見出せないので、検討する気にはなりません。


CC BY-SA 3.0
2016-10-18T12:07:22.830
29669
2016-10-18T12:07:22.830
18540
29663
answer