50293

[code]

    class HogeVC: UIViewController {
        var id: Int?
    
        init(id: Int) {
            super.init() // Must call a designated initializer of the superclass 'UIViewController'
    
            self.id = id
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
        }
    
    
    }
    
[/code]

上記コード内のコメントにも記載しましたが、

> Must call a designated initializer of the superclass 'UIViewController'

というエラーがでました。

この問題は  
`super.init()`を  
`super.init(nibName: nil, bundle: nil)`に書き換えることで対応できました。

ここで疑問がでました。

  * なぜ、`UIViewController`は`super.init()`を呼べないのでしょうか？
  * 自分で `Must call a designated initializer of the superclass '....'` を起こすような親クラスを作ることは可能なのでしょうか？


CC BY-SA 4.0
2018-11-13T09:21:18.070
50286
2018-11-13T11:55:05.800
9008
question
swift ios
UIViewControllerのサブクラスのカスタムinitでsuper.initを呼べないのは何故ですか？


  * **_なぜ、UIViewControllerはsuper.init()を呼べないのでしょうか？_**

`UIViewController.init()`はdesignated
initializer(指定イニシャライザ、または、指名イニシャライザ、と訳されることが多いようです)ではないからです。

Swiftのイニシャライザには小うるさい規則がいくつもあって、それらは緩いObjective-
Cの世界とはうまく動かなかったりするのですが、ここら辺に明記してあります。

[Class Inheritance and Initialization](https://docs.swift.org/swift-
book/LanguageGuide/Initialization.html#ID216)

> ## Initializer Delegation for Class Types
>
> ### Rule 1
>
> A designated initializer must call a designated initializer from its  
>  immediate superclass.
>
> ## クラス型の初期化の委譲について
>
> ### 規則1
>
> 指名イニシャライザは直接のスーパークラスの指名イニシャライザのどれかを呼ばなければいけません。

あなたの`init(id:)`には`convenience`と言うキーワードがついていませんから、「指名イニシャライザ」を定義しているものと解釈されます。従って、規則1により、直接のスーパークラスである`UIViewController`の指名イニシャライザをその中で呼ぶ必要があります。

つまり指名イニシャライザ`init(id:)`の定義中では、`UIViewController`の指名イニシャライザである`init(nibName:bundle:)`または`init?(coder:)`(こっちは単なる指名イニシャライザではなく、必須イニシャライザでもありますが)のどちらかを呼んでやらないとエラーになります。

  * **_自分で Must call a designated initializer of the superclass '....' を起こすような親クラスを作ることは可能なのでしょうか？_**

「`init()`と言うシグニチャーのイニシャライザは存在するが、それは指名イニシャライザではない」と言うクラスを定義すれば、すぐに再現可能です。

[code]

    class MyClass {
        var name: String
    
        init(name: String) {
            self.name = name
        }
    
        convenience init() {
            self.init(name: "")
        }
    }
    
    class DerivedClass: MyClass {
        var id: Int?
    
        init(id: Int) {
            self.id = id
    
            super.init() //-> Must call a designated initializer of the superclass 'MyClass'
        }
    }
    
[/code]

* * *

Objective-Cで定義された`NSObject`の子孫クラスでは、Objective-Cの特性上、`NSObject`で定義されている`-
(instancetype)init`というイニシャライザ(Swiftに移入されると`init()`)を無かったことには出来ないのですが、多くのクラスで`init()`はドキュメント化されてもいない動作不詳のイニシャライザです。`super.init()`が通用するクラスであっても、その動作がドキュメントで明記されていない限り、呼ばない方が良いでしょう。


CC BY-SA 4.0
2018-11-13T11:24:11.173
50293
2018-11-13T11:55:05.800
2018-11-13T11:55:05.800
13972
13972
50286
answer