如何在Swift中实现具有相同内容的两个没有代码重复的内容? [英] How to implement two inits with same content without code duplication in Swift?

查看:68
本文介绍了如何在Swift中实现具有相同内容的两个没有代码重复的内容?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设一个派生自 UIView 的类如下:

Assume a class that is derived from UIView as follows:

class MyView: UIView {
    var myImageView: UIImageView

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

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

    ...

如果我想在两个初始值设定项中使用相同的代码,例如

If I wanted to have the same code in both of the initializers, like

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

在类实现中没有重复那段代码两次,我将如何构建 init 方法?

and NOT duplicate that code twice in the class implementation, how would I structure the init methods?

尝试方法:


  • 创建方法 func在 super.init 之后调用的commonInit() - > Swift编译器提供有关未初始化变量的错误le myImageView 在致电 super.init

  • 之前调用 func commonInit()之前 super.init 在super.init调用之前使用编译器错误'self'自我失败

  • Created a method func commonInit() that is called after super.init -> Swift compiler gives an error about an uninitialized variable myImageView before calling super.init
  • Calling func commonInit() before super.init fails self-evidently with a compiler error "'self' used before super.init call"

推荐答案

我刚才有同问题

正如GoZoner所说,将变量标记为可选将起作用。这不是一种非常优雅的方式,因为每次要访问它时都需要打开值。

As GoZoner said, marking your variables as optional will work. It's not a very elegant way because you then have to unwrap the value each time you want to access it.

我会向Apple提交增强请求,也许我们可以得到类似beforeInit方法的东西,在每个init之前调用,我们可以分配变量,所以我们不要不必使用可选的变量。

I will file an enhancement request with Apple, maybe we could get something like a "beforeInit" method that is called before every init where we can assign the variables so we don't have to use optional vars.

在此之前,我将把所有赋值放入一个从专用初始化程序调用的commonInit方法中。例如:

Until then, I will just put all assignments into a commonInit method which is called from the dedicated initialisers. E.g.:

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
    }
}






感谢大卫我看过这本书再一次,我找到了一些可能对我们的重复数据删除工作有所帮助,而不必使用可选的变量hack。可以使用闭包来初始化变量。


Thanks to David I had a look at the book again and I found something which might be helpful for our deduplication efforts without having to use the optional variable hack. One can use a closure to initialize a variable.


使用关闭或功能设置默认属性值

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

If a stored property’s default value requires some customization or setup, you can use a closure or global function to provide a customized default value for that property. Whenever a new instance of the type that the property belongs to is initialized, the closure or function is called, and its return value is assigned as the property’s default value. These kinds of closures or functions typically create a temporary value of the same type as the property, tailor that value to represent the desired initial state, and then return that temporary value to be used as the property’s default value.

这是一个关于如何使用闭包来提供默认属性值的骨架轮廓:

Here’s a skeleton outline of how a closure can be used to provide a default property value:

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立即执行关闭。如果省略这些括号,则试图将闭包本身分配给属性,而不是闭包的返回值。

Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately. If you omit these parentheses, you are trying to assign the closure itself to the property, and not the return value of the closure.

注意

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

If you use a closure to initialize a property, remember that the rest of the instance has not yet been initialized at the point that the closure is executed. This means that you cannot access any other property values from within your closure, even if those properties have default values. You also cannot use the implicit self property, or call any of the instance’s methods.

摘自:Apple Inc.The Swift Programming Language。iBooks。 https://itun.es/de/jEUH0.l

Excerpt From: Apple Inc. "The Swift Programming Language." iBooks. https://itun.es/de/jEUH0.l

这是我从现在开始使用的方式,因为它没有规避不允许nil变量的有用功能。对于我的例子,它看起来像这样:

This is the way I will use from now on, because it does not circumvent the useful feature of not allowing nil on variables. For my example it'll look like this:

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()
    }
}

这篇关于如何在Swift中实现具有相同内容的两个没有代码重复的内容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆