64

我无法将 init 方法添加到以下 UIViewController 类。我需要在 init 方法中编写一些代码。我必须编写 init(coder) 方法吗?即使我添加了编码器和解码器方法,我仍然会出错。我也尝试使用不带任何参数的 init 方法,但这似乎也不起作用。

class ViewController: UIViewController {

    var tap: UITapGestureRecognizer?

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)   {
        super.init(nibName: nil, bundle: nil)
        tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    }

...
...
}

如果我在没有参数的情况下调用 super.init() 方法,则错误是“必须调用超类的指定初始化程序”,如果我传递参数 nib 和 bundle,则错误是“必需的初始化程序 init(coder)”。

即使我添加了 init(coder) 和 init(decoder) 它也不起作用。

4

8 回答 8

68

我用了:

convenience init() {
    self.init(nibName:nil, bundle:nil)
}

有人建议:

convenience init(){
    self.init()
}

但这会给你一个无限循环。

于 2015-09-02T18:26:39.657 回答
41

所有这些答案都是半答案。有些人在相关帖子中遇到了无限循环,因为他们只是添加了convenience init()(如果你不提供一个独特的init()方法来调用它,它会递归地调用自己),而其他人却忽略了扩展超类。这种格式结合了所有解决方案来完全满足问题。

// This allows you to initialise your custom UIViewController without a nib or bundle.
convenience init() {
    self.init(nibName:nil, bundle:nil)
}

// This extends the superclass.
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
}

// This is also necessary when extending the superclass.
required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented") // or see Roman Sausarnes's answer
}

编辑:此外,如果您想使用传递给您的convenience init()方法的参数初始化任何类属性,而不会抱怨所有被覆盖的init()方法,那么您可以将所有这些属性设置为隐式展开的可选项,这是Apple 自己使用的模式。

于 2017-04-20T16:44:43.147 回答
28

您需要覆盖init(nibName:bundle:)初始化程序,提供init(coder:)所需的初始化程序,并tap在两者中进行初始化:

class ViewController: UIViewController {

    var tap: UITapGestureRecognizer?

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)   {
        print("init nibName style")
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    }

    // note slightly new syntax for 2017
    required init?(coder aDecoder: NSCoder) {
        print("init coder style")
        super.init(coder: aDecoder)
        tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    }
...
...
}

nil另外,请确保在调用超类初始化程序时不要只传递nibNameand bundle。你应该放弃传入的任何内容。


请注意,某些答案中提到的“便利初始化”方法仅在您实际上是“手动”自己初始化视图控制器时才相关。(在极少数情况下你会这样做。)如果你想“在正常初始化期间做某事” - 例如创建一个手势识别器或只是初始化一些变量 - 唯一可能的解决方案正是这个答案中给出的那个.

于 2015-09-02T19:23:06.713 回答
8

您可以只创建一个便利初始化程序,便利初始化程序不会覆盖 init() 而只是调用它使事情变得更容易。

class ViewController: UIViewController {
    var tap: UITapGestureRecognizer?
    convenience init(){
        self.init()
        tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    }
}
于 2015-06-06T05:24:05.920 回答
6

我认为你必须添加

required init(coder aDecoder: NSCoder) {
    print("init coder")
    super.init(coder: aDecoder)
}

或者

convenience init() {
    self.init()
}

你也必须写 init 。不要删除它

var tap: UITapGestureRecognizer?

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)   {
    super.init(nibName: nil, bundle: nil)
}

希望能帮助到你

于 2015-06-06T05:21:23.877 回答
3

我遇到了很久很久以前问过的这个问题。但没有人提供这个问题的基本答案。这是 Swift 的一个基本原则:- 子类必须在它的超类初始化完成之前初始化它的变量。

因此,正如Ankit Goel提到的崩溃:-“必须调用超类的指定初始化程序”

因此更新的代码将是: -

class ViewController: UIViewController {
    var tap: UITapGestureRecognizer?

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)   {
        print("init nibName style")
        self.tap = nil
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        self.tap = UITapGestureRecognizer(target: self, action: Selector(("handleTap:")))
    }

    required init?(coder aDecoder: NSCoder) {
        print("init coder style")
        self.tap = nil
        super.init(coder: aDecoder)
        tap = UITapGestureRecognizer(target: self, action: Selector(("handleTap:")))
    }
}
于 2017-11-30T13:51:16.187 回答
2

我在 Xcode 12.0 中遇到了与 Swift 5 相同的问题,这是我在 2020 年的解决方案。

class Foo: UIViewController {
    private var bar: Bar!

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

        setupController()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        setupController()
    }
    
    private func setupController() {
        bar = Bar()
    }
}

我正在使用的另一种方法是在函数内部进行初始化loadView

class Foo: UIViewController {
    private var bar: Bar!
    
    override func loadView() {
        setupController()
    }

    private func setupController() {
        bar = Bar()
    }
}
于 2020-09-29T10:36:52.553 回答
1

正确的流程是,调用指定的初始化程序,在这种情况下是带有 nibName 的初始化程序,

init(tap: UITapGestureRecognizer)
{
    // Initialise the variables
    tap = UITapGestureRecognizer(target: self, action: Selector(("handleTap:")))

    // Call the designated init of ViewController
    super.init(nibName: nil, bundle: nil)

    // Call your viewcontroller custom methods here
    setupViewControllers()
}
于 2020-06-07T07:33:42.340 回答