一尘不染

如何在Swift中在没有代码重复的情况下实现具有相同内容的两个init?

swift

假定派生自UIView以下类的类:

class MyView: UIView {
    var myImageView: UIImageView

    init(frame: CGRect) {
        super.init(frame: frame)
    }

    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder)
    }

    ...

如果我想在两个初始化器中都使用相同的代码,例如

self.myImageView = UIImageView(frame: CGRectZero)
self.myImageView.contentMode = UIViewContentMode.ScaleAspectFill

并且 不要 在类实现中 重复 两次 该代码 ,我将如何构造init方法?

尝试的方法:

  • 创建一个func commonInit()super.init-> Swift编译器myImageView在调用之前给出有关未初始化变量的错误之后调用的方法super.init
  • func commonInit()之前的调用super.init显然失败,并出现编译器错误 “ super.init调用之前使用了’self’

阅读 315

收藏
2020-07-07

共1个答案

一尘不染

正如GoZoner所说,将变量标记为可选将起作用。这不是一种非常优雅的方法,因为您每次访问该值时都必须解开该值。

我将向Apple提出增强请求,也许我们可以得到类似“
beforeInit”方法的信息,该方法在每次可以分配变量的init之前调用,因此我们不必使用可选的var。

在此之前,我将所有分配都放到commonInit方法中,该方法从专用的初始化程序中调用。例如:

class GradientView: UIView {
    var gradientLayer: CAGradientLayer?  // marked as optional, so it does not have to be assigned before super.init

    func commonInit() {
        gradientLayer = CAGradientLayer()
        gradientLayer!.frame = self.bounds
        // more setup 
    }

    init(coder aDecoder: NSCoder!)  {
        super.init(coder: aDecoder)
        commonInit()
    }

     init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        gradientLayer!.frame = self.bounds  // unwrap explicitly because the var is marked optional
    }
}

多亏了戴维(David),我再次看了一本书,发现了一些不必使用可选变量hack就能对重复数据删除工作有所帮助的东西。可以使用闭包来初始化变量。

使用闭包或函数设置默认属性值

如果存储的属性的默认值需要一些自定义或设置,则可以使用闭包或全局函数为该属性提供自定义的默认值。每当初始化属性所属类型的新实例时,都会调用闭包或函数,并将其返回值分配为属性的默认值。这些类型的闭包或函数通常会创建与属性相同类型的临时值,定制该值以表示所需的初始状态,然后返回该临时值以用作属性的默认值。

这是有关如何使用闭包提供默认属性值的框架概述:

class SomeClass {
let someProperty: SomeType = {
    // create a default value for someProperty inside this closure
    // someValue must be of the same type as SomeType
    return someValue
    }()
}

请注意,闭包的末大括号后跟一对空括号。这告诉Swift立刻执行关闭。如果省略这些括号,则尝试将闭包本身分配给属性,而不是闭包的返回值。

注意

如果使用闭包来初始化属性,请记住在执行闭包时实例的其余部分尚未初始化。这意味着您无法从闭包内部访问任何其他属性值,即使这些属性具有默认值也是如此。您也不能使用隐式的self属性,或调用实例的任何方法。

摘录自:苹果公司“ The Swift Programming
Language”。iBooks。https://itun.es/de/jEUH0.l

从现在开始,我将使用这种方式,因为它不会绕过不允许对变量使用nil的有用功能。对于我的示例,它将如下所示:

class GradientView: UIView {
    var gradientLayer: CAGradientLayer = {
        return CAGradientLayer()
    }()

    func commonInit() {
        gradientLayer.frame = self.bounds
        /* more setup */
    }

    init(coder aDecoder: NSCoder!)  {
        super.init(coder: aDecoder)
        commonInit()
    }

    init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
}
2020-07-07