gpt4 book ai didi

swift - 在 Swift 中初始化 UIViews 的惯用模式

转载 作者:搜寻专家 更新时间:2023-10-31 08:34:00 25 4
gpt4 key购买 nike

Objective-C 中,我发展了同时拥有 awakeFromNibinitWithFrame: 方法的模式,后者调用了它们的 super 的,然后调用一个 _commonInit,我把我自己的所有代码都放在那里。例如

- (void)_commonInit {
// Initialize stuff here
}

- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self _commonInit];
}
return self;
}

- (void)awakeFromNib {
[super awakeFromNib];
[self _commonInit];
}

所以我试图在我移植到 Swift 的 UIView 子类中重用这个模式:

func _commonInit() {
// initialize code here
}

override init(frame:CGRect) {
super.init(frame:frame)
self._commonInit()
}

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

override func awakeFromNib() {
super.awakeFromNib()
self._commonInit()
}

这是正确的做法吗?我很好奇为什么 init(coder...)必需的。特别是当我所做的只是调用 super 版本时。我似乎记得我在 Objc 版本中使用 awakeFromNib 的原因是因为从 nib 恢复应用的任何更改直到晚于 initFromCoder:.

最佳答案

拥有一个从你的初始化器调用的 commonInit 方法对于你有多个指定(或要求)初始化器的情况来说是一个完美的模式。不过,这不是唯一的模式。

依次解决你的每一个疑惑(并补充一些相关的要点)...

  • init(coder:) 是必需的,因为您正在子类化声明符合 NSCoding 协议(protocol)的类。该协议(protocol)要求所有子类的所有实例都能够从存档中初始化。

    不过,您实际上不必在 init(coder:) 中执行任何操作,除非您将状态保存在 encodeWithCoder(_:) 中。但是因为子类可能具有未继承的可编码状态,所以初始化安全要求子类负责此初始化程序(即使它所做的只是调用 super)。

  • 您在从 nib/ Storyboard加载的任何自定义类中使用 awakeFromNib() 来处理仅在连接对象的导出和操作后才需要发生的初始化。

    当 Cocoa (Touch) 加载一个 nib 时,它首先初始化每个对象(使用 init(coder:) ),然后在所有对象“事件”之后,它连接所有 IBOutlet 变量和控件发送的所有 IBAction 的目标.完成所有这些后,它调用 awakeFromNib()

  • 在 Swift 中使用 commonInit 模式有一个警告——甚至是一个悖论:您必须在调用 super.init() 之前初始化属性(又名实例变量),并且您不能访问 self(包括调用 self 上的方法) ) 直到调用 super.init() 之后。因此,您不能使用 commonInit 方法来设置属性的初始值。

    可以具有类型为隐式展开的可选类型的属性。这些会自动初始化为 nil ,然后您可以在 commonInit 方法中设置一个“真实的”初始值:

    var name: String!
    init(frame: CGRect) {
    super.init(frame: frame)
    self.commonInit()
    }
    init(coder: NSCoder) {
    super.init(coder: coder)
    self.commonInit()
    }
    private func commonInit() {
    name = // something...
    }

解决此问题的另一种模式是为每个属性提供初始值设定项(甚至惰性初始值设定项)。如果这样做,则不需要 commonInit 方法,因为将从实际使用的 init 中隐式调用属性初始值设定项(或者在惰性初始值设定项的情况下,当首次访问属性时)。

class MyView: UIView {
let fileManager = NSFileManager.defaultManager()
let appDelegate = UIApplication.sharedApplication().delegate as! MyAppDelegate
lazy var name: String = { /* compute here */ }()
init(frame: CGRect) { super.init(frame: frame) }
init(coder: NSCoder) { super.init(coder: coder) }
// ...
}

最后,如果你确实提供了一个 commonInit(或类似的)方法,你不需要用初始下划线或任何东西来破坏名称——Swift 有内置的访问控制,所以任何您不想向类外的调用者公开的方法可以简单地标记为 private

关于swift - 在 Swift 中初始化 UIViews 的惯用模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29956195/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com