【问题标题】:Why must I keep declaring the same required but not implemented initializer for init(coder aDecoder) for my programatic UIViewController subclass?为什么我必须继续为我的程序化 UIViewController 子类的 init(coder aDecoder) 声明相同的必需但未实现的初始化程序?
【发布时间】:2023-03-30 20:25:01
【问题描述】:

也许只有我一个人,但我发现 swift 的某些方面……至少可以说是迟钝的。

我大部分时间都不使用 Interface Builder,因为我喜欢使用 PureLayout。所以我希望创建一个UIViewController 子类,比如PureViewController,它有一个方便的init,不带参数:

class PureViewController : UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
    }

}

但这不行,因为 XCode 告诉我我还必须实现 init(coder aDecoder: NSCoder)。好的,没关系!这就是我创建这个类的原因——所以我不必为子类再次这样做。

class PureViewController : UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

好的,现在这就是我不明白的。

我定义了一个子类SomePureViewController : PureViewController,带有一个初始化器init(viewModel:ICrackersViewModel)...

class SomePureViewController : PureViewController {

    init(viewModel:ICrackersViewModel) {
        super.init()
    }

}

但它仍然要我定义相同的愚蠢初始化器,直到王国来临!

class SomePureViewController : PureViewController {

    init(viewModel:ICrackersViewModel) {
        super.init()
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

现在我理解了这个想法 - 我的子类中没有 init(decoder),即使它是在其父类中定义的。

也许我一直用UIViewController 处理这个问题,但以前从未注意到它。

我的问题如下:

  1. 是我做错了什么导致了这种行为吗?
  2. 除了继承之外,我还有什么方法可以避免重复自己吗?
  3. 是否有计划改变这种情况?

【问题讨论】:

    标签: ios swift uiviewcontroller designated-initializer


    【解决方案1】:

    关键是只要知道基类型就可以初始化一个可能的派生类。

    让我们假设一个基类

    class Base {
        let value: Int
    
        required init(value: Int) {
            self.value = value
        }
    }
    

    还有一个函数

    func instantiateWith5(cls: Base.Type) -> Base {
        return cls.init(value: 5)
    }
    

    那么我们就可以了

    let object = instantiateWith5(Base.self)
    

    现在如果有人定义了派生类

    class Derived: Base {
        let otherValue: Int
    
        init() {
            otherValue = 1
            super.init(value: 1)
        }
    
        required init(value: Int) {
            fatalError("init(value:) has not been implemented")
        }
    }
    

    我们至少可以打电话

    let object2 = instantiateWith5(Derived.self)
    

    违反 LSP,但这是您的代码问题,而不是语言问题。

    Swift 必须保证初始化器让你的对象处于初始化状态,即使它们是从基础对象派生的,所以我想改变这将是一件坏事。如果您想定义一个不可反序列化并因此违反 LSP 的 UIViewController,这是您的决定 - 但不要指望语言在这方面支持您。

    【讨论】:

    • 好答案。我将需要更多地使用它才能真正“得到它”,但我仍然觉得这只是出于某种原因迅速出现的问题。或者更确切地说,也许是required 是只有 swift 才有的功能。
    【解决方案2】:

    我认为这是一个快速的问题,没有办法避免这种情况。我们都讨厌这个空的——致命的错误初始化器。

    【讨论】:

      【解决方案3】:

      由于初始化器用required 关键字标记,所有子类都必须实现该初始化器,并且它们还必须在其实现中指定required,以便它们的 子类也需要实现它。

      必需的初始化器

      在前面写上所需的修饰符 定义一个类初始值设定项来指示每个子类 该类必须实现该初始化程序

      您还必须在所需初始化程序的每个子类实现之前编写 required 修饰符,以指示初始化程序要求适用于链中的其他子类。”

      自 1.0 以来,这一直是 Swift 语言的一部分,并且不太可能改变。

      这个问题实际上与 UIViewController 类定义中 required 关键字的使用有关。理论上这可以改变,但我再次认为这不太可能。

      【讨论】:

        猜你喜欢
        • 2014-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-10
        • 1970-01-01
        • 2014-07-25
        相关资源
        最近更新 更多