ios:有关init(frame :)和init的问题?(编码器:)

时间:2017-12-03 16:22:57

标签: ios xcode uiview initwithcoder initwithframe

Apple的教程将init(frame:)init?(coder:)之间的区别描述为

  

您通常使用以下两种方式之一创建视图:通过编程方式   初始化视图,或允许视图加载   故事板。每种方法都有相应的初始化程序:   init(frame:)以编程方式初始化视图和   init?(coder:)用于从故事板加载视图。你会需要   在自定义控件中实现这两种方法。而   设计应用程序,Interface Builder以编程方式实例化   将其添加到画布时查看。在运行时,您的应用加载   从故事板中查看。

我对“程序初始化”和“由故事板加载”的描述感到困惑。假设我有一个名为UIView的{​​{1}}的子类,“程序初始化”意味着我编写代码以将MyView的实例添加到以下某处:

MyView

override func viewDidLoad() { super.viewDidLoad() let myView = MyView() // init(frame:) get invoked here?? } 时调用init?(coder:)我从对象库拖动Main.storyboard,然后在身份检查器中将其类设置为{{1 }}?

此外,在我的xcode项目中,这两种方法最终使用不同的模拟器布局和 UIView 使用相同的代码: enter image description here

MyView

他们为什么表现不一样? (我从对象库拖动Main.storyboard并将其类设置为RecordView)

2 个答案:

答案 0 :(得分:2)

  

我对描述"程序初始化"感到很困惑。和#34;由故事板加载"。

基于对象的编程是关于类和实例的。您需要创建一个类的实例。使用Xcode,有两种截然不同的方法来获取类的实例:

  • 您的代码会创建实例

  • 你加载一个笔尖(这样一个视图控制器在故事板中的视图),nib加载过程创建实例并交给你

在这两种情况下调用的初始化程序是不同的。如果您的代码创建了UIView实例,则必须调用的指定初始值设定项为init(coder:)。但是如果nib创建视图,则nib加载进程调用的指定初始化程序为{{1}}。

因此,如果您有一个UIView子类并且想要覆盖初始化器,则必须考虑将调用哪个初始化器(基于如何创建视图实例)。

答案 1 :(得分:1)

首先,您在init?(coder:)init(frame:)之间的划分基本上是正确的。在实际运行应用程序时实例化故事板场景时使用前者,但是当您使用let foo = RecordView()let bar = RecordView(frame: ...)以编程方式对其进行实例化时,将使用后者。此外,在IB中预览init(frame:)次观看时会使用@IBDesignable

其次,关于您的问题,我建议您从center删除fillView setupFillView的设置(以及角半径内容)。问题是,当init被调用时,您通常不会知道bounds最终会是什么。您应该在center中设置layoutSubviews,每次视图更改大小时都会调用class RecordView: UIView { // this is the black circle with a white border private var fillView = UIView() // this is the inner red circle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupFillView() } override init(frame: CGRect = .zero) { super.init(frame: frame) setupFillView() } private func setupFillView() { fillView.backgroundColor = .red self.addSubview(fillView) } override func layoutSubviews() { super.layoutSubviews() let radius = (cornerRadius - borderWidth) * 0.95 // these are not defined in this snippet, but I simply assume you omitted them for the sake of brevity? fillView.frame = CGRect(origin: .zero, size: CGSize(width: radius * 2, height: radius * 2)) fillView.layer.cornerRadius = radius fillView.center = CGPoint(x: bounds.midX, y: bounds.midY) } }

Class