如何实现两个相同的内容在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方法?

试过的方法:

  • 创build了一个方法func commonInit()super.init之后func commonInit() – > Swift编译器在调用super.init之前给出了有关未初始化variablesmyImageView的错误
  • super.init调用func commonInit()之前,显然会失败,编译器错误在super.init之前调用“self”

我只是有同样的问题 。

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

我将向Apple提交一个增强请求,也许我们可以得到类似于“beforeInit”方法的东西,该方法在每个可以分配variables的init之前调用,所以我们不必使用可选的variables。

在那之前,我将把所有的任务都放到一个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,我又看了一遍这本书,发现了一些可能有助于重复数据删除的工作,而不必使用可选的variableshack。 可以使用闭包来初始化一个variables。

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

如果存储属性的默认值需要一些定制或设置,则可以使用闭包或全局函数为该属性提供定制的默认值。 只要属性所属types的新实例被初始化,就调用闭包或函数,并将其返回值指定为属性的默认值。 这些types的闭包或函数通常创build与属性相同types的临时值,定制该值来表示所需的初始状态,然后返回该临时值以用作属性的缺省值。

下面是关于如何使用闭包来提供默认属性值的框架:

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

注意

如果您使用闭包来初始化一个属性,请记住,在执行闭包的位置,其余的实例尚未初始化。 这意味着即使这些属性具有默认值,也无法从您的闭包中访问任何其他属性值。 您也不能使用隐式自我属性,或者调用任何实例的方法。

摘录自:苹果公司“Swift编程语言”,iBooks。 https://itun.es/de/jEUH0.l

这是我从现在开始使用的方式,因为它没有规避不允许零variables的有用特性。 对于我的例子,它会看起来像这样:

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

我们需要的是在调用任何超类的初始化器之前放置我们的初始化代码的一个常见的地方,所以我现在使用的是下面的代码。 (它也涵盖违约之间相互依赖的情况,并保持不变。)

 import UIKit class MyView: UIView { let value1: Int let value2: Int enum InitMethod { case Coder(NSCoder) case Frame(CGRect) } override convenience init(frame: CGRect) { self.init(.Frame(frame))! } required convenience init?(coder aDecoder: NSCoder) { self.init(.Coder(aDecoder)) } private init?(_ initMethod: InitMethod) { value1 = 1 value2 = value1 * 2 //interdependence among defaults switch initMethod { case let .Coder(coder): super.init(coder: coder) case let .Frame(frame): super.init(frame: frame) } } } 

这个怎么样?

 public class MyView : UIView { var myImageView: UIImageView = UIImageView() private func setup() { myImageView.contentMode = UIViewContentMode.ScaleAspectFill } override public init(frame: CGRect) { super.init(frame: frame) setup() } required public init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } } 

这一定是否来过? 我认为这是隐含的解包选项可用于的一个方面:

 class MyView: UIView { var myImageView: UIImageView! init(frame: CGRect) { super.init(frame: frame) self.commonInit() } init(coder aDecoder: NSCoder!) { super.init(coder: aDecoder) self.commonInit() } func commonInit() { self.myImageView = UIImageView(frame: CGRectZero) self.myImageView.contentMode = UIViewContentMode.ScaleAspectFill } ... } 

隐式解包的选项允许您在调用super之前跳过variables赋值。 但是,您仍然可以像正常variables一样访问它们:

var image: UIImageView = self.myImageView // no error

在基于单个图像创build函数的init()方法中分配myImageView 。 因此:

 self.myImageView = self.createMyImageView (); 

例如,像这样:

 class Bar : Foo { var x : Int? func createX () -> Int { return 1 } init () { super.init () self.x = self.createX () } } 

请注意“可选”在Int?使用Int?

另一个select使用静态方法(添加'otherView'来突出可伸缩性)

 class MyView: UIView { var myImageView: UIImageView var otherView: UIView override init(frame: CGRect) { (myImageView,otherView) = MyView.commonInit() super.init(frame: frame) } required init(coder aDecoder: NSCoder) { (myImageView, otherView) = MyView.commonInit() super.init(coder: aDecoder)! } private static func commonInit() -> (UIImageView, UIView) { //do whatever initialization stuff is required here let someImageView = UIImageView(frame: CGRectZero) someImageView.contentMode = UIViewContentMode.ScaleAspectFill let someView = UIView(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) return (someImageView, someView) } }