如何在Swift中为UIView子类编写自定义init?


125

假设我想使用a 和an init作为UIView子类。StringInt

如果我只是继承子类,我将如何在Swift中做到这一点UIView?如果我只是做一个自定义init()函数,但是参数是一个String和一个Int,它告诉我“从初始化返回之前没有调用super.init()”。

如果我打电话给super.init()我,我必须使用指定的初始化程序。我应该在那里使用什么?框架版本?编码器版本?都?为什么?

Answers:


207

init(frame:)版本是默认的初始化程序。您必须在初始化实例变量之后才调用它。如果从Nib重构此视图,那么将不会调用您的自定义初始化程序,而是init?(coder:)会调用版本。由于Swift现在需要实现required的实现,因此init?(coder:)我更新了以下示例,并将let变量声明更改为varand可选。在这种情况下,您可以在awakeFromNib()或稍后进行初始化。

class TestView : UIView {
    var s: String?
    var i: Int?
    init(s: String, i: Int) {
        self.s = s
        self.i = i
        super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
    }

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

5
然后一定要使它们var。但是Swift中的默认最佳实践是声明变量,let除非有理由声明它们var。因此,在我上面的代码示例中没有这样的理由let
Wolf McNally 2014年

2
此代码无法编译。您需要实现所需的初始化程序init(coder:)
Decade Moon

3
有趣的是几年前如何编写的。如今,它在init(coder :)下抱怨“属性self.s未在super.init调用中初始化”
mafiOSo

修复了Swift 3.1的示例。在导入UIKit的操场下编译。
Wolf McNally

1
我制作了@LightNight,s并且iOptional是为了使事情保持简单。如果它们不是可选的,则还需要在所需的初始化程序中对其进行初始化。将它们设置为可选意味着它们将nilsuper.init()被调用时出现。如果它们不是可选的,则确实需要在调用super.init()之前对其进行分配。
Wolf McNally

32

我为指定的和必需的创建一个通用的init。为了方便起见,我将init(frame:)零帧委托给它。

零帧不是问题,因为通常该视图在ViewController的视图内;您的自定义视图将在父视图调用layoutSubviews()或时获得一个安全的机会来布局其子视图updateConstraints()。系统在整个视图层次结构中递归调用这两个函数。您可以使用updateContstraints()layoutSubviews()updateContstraints()首先被调用,然后被调用layoutSubviews()。在updateConstraints()请确保调用超级最后。在layoutSubviews(),叫超级第一

这是我的工作:

@IBDesignable
class MyView: UIView {

      convenience init(args: Whatever) {
          self.init(frame: CGRect.zero)
          //assign custom vars
      }

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

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

      override func prepareForInterfaceBuilder() {
           super.prepareForInterfaceBuilder()
           commonInit()
      }

      private func commonInit() {
           //custom initialization
      }

      override func updateConstraints() {
           //set subview constraints here
           super.updateConstraints()
      }

      override func layoutSubviews() {
           super.layoutSubviews()
           //manually set subview frames here
      }

}

1
它不起作用:在super.init初始化自身之前,在方法调用“ commonInit”中使用“ self”
surfrider

1
在self.init调用之后初始化自定义参数。更新了我的答案。
MH175

1
但是,如果要在commonInit方法中初始化某些属性,但是super在这种情况下不能放置在该属性之后,该怎么办,因为您应该在super调用之前初始化所有属性。大声笑似乎死循环。
2017年

1
Swift初始化通常是这样工作的:搜索“两阶段初始化”。您可以使用隐式解包的可选内容,但我建议您反对使用它。您的体系结构(尤其是在处理视图时)应初始化所有本地属性。我现在已经将此commonInit()方法用于数百个视图。它有效
MH175

17

这是我在Swift 9中的iOS 9上执行的操作-

import UIKit

class CustomView : UIView {

    init() {
        super.init(frame: UIScreen.mainScreen().bounds);

        //for debug validation
        self.backgroundColor = UIColor.blueColor();
        print("My Custom Init");

        return;
    }

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

这是带有示例的完整项目:


2
这会将整个显示用于视图
RaptoX

1
是的 如果有兴趣的部分子视图,让我知道,我会后这个问题,以及
J-Dizzle

1
我最喜欢这个答案,因为拥有fatalError意味着我不必在所需的init中放入任何代码。
卡特·梅德林

1
@ J-Dizzle,我想看看局部视图的解决方案。
阿里·拉森斯基

您的答案不是说与已接受的答案相反吗?我的意思是您要在之后进行自定义super.init,但他说应该在super.init... 之前完成
亲爱的,

11

这是我在Swift中的iOS上做子视图的方法-

class CustomSubview : UIView {

    init() {
        super.init(frame: UIScreen.mainScreen().bounds);

        let windowHeight : CGFloat = 150;
        let windowWidth  : CGFloat = 360;

        self.backgroundColor = UIColor.whiteColor();
        self.frame = CGRectMake(0, 0, windowWidth, windowHeight);
        self.center = CGPoint(x: UIScreen.mainScreen().bounds.width/2, y: 375);

        //for debug validation
        self.backgroundColor = UIColor.grayColor();
        print("My Custom Init");

        return;
    }

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

4
很好地使用fatalError()调用。我不得不使用可选参数来使来自甚至没有使用过的初始化程序的警告静音。这把它关闭了!谢谢。
Mike Critchley
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.