В подклассах Swift ниже, когда вызывается ChildView(dummy: NSObject())
, будут вызваны два разных назначенных инициализатора для ParentView, и myLayer
ivar ParentView
будет инициализирован дважды.
Не то чтобы этоне произойдет на игровой площадке - это правильно сообщит, что error: MyPlayground.playground:5:31: error: must call a designated initializer of the superclass 'NSView'
Однако в проекте XCode (например, инструмент командной строки) это скомпилируется и будет работать нормально.
Я понимаюмного чего происходит и как предотвратить эту проблему.Но я бы хотел понять, почему компилятор не дает ошибок, или, по крайней мере, предупредить меня об этом коде (и предотвратить двойную инициализацию)
Этот код компилируется чисто под Swift 4.2, и в отладчике я могуточно видеть, что происходит:
Когда вызывается ChildView(dummy:)
, он вызывает ParentView(dummy:)
Это назначенный инициализатор, инициализируются ли ивары ParentView (myLayer
)
Затем ParentView(dummy:)
вызывает super.init()
, что составляет NSView.init()
Реализация NSView.init () вызывает initWithFrame
, поэтому ChildView.init(frame:)
вызывается и вызывается ParentView.init(frame:)
.Это также назначенный инициализатор, поэтому myLayer
инициализируется во второй раз.
Чтобы продемонстрировать это, учитывая приведенные ниже классы, вызовите
let _ = ChildView(dummy: NSObject)
>>>> creating layer
будет напечатан дважды.
Чтобы избежать этого, нужно набрать ParentView(dummy:)
call super.init(frame:)
, и тогда проблема исчезнет.
Мой вопрос действительно, как это могло случиться?произойдет в первую очередь?
import Cocoa
class ParentView: NSView {
private var myLayer: CALayer = {
print(">>>> creating layer")
return CALayer()
}()
override init(frame frameRect: NSRect) { super.init(frame: frameRect) }
required init?(coder decoder: NSCoder) { super.init(coder: decoder) }
init(dummy: AnyObject?) { self.init() }
}
class ChildView: ParentView {
override init(frame frameRect: NSRect) { super.init(frame: frameRect) }
required init?(coder decoder: NSCoder) { super.init(coder: decoder) }
override init(dummy: AnyObject?) { super.init(dummy: dummy) }
}
Это должно генерировать ошибку времени компиляции, как это происходит на игровой площадке.
Кажется, я не могу построитьподобная не-NSView классовая иерархия, которая дает такое же поведение.Независимо от того, как я настраиваю иерархию, конструкторы и т. Д., Swift всегда выдает ошибки компилятора, когда я пытаюсь сделать это с новыми объектами (даже когда я смешиваю Objective-C и Swift, чтобы быть аналогичным NSView.
Iне могу найти ни одного публичного объявления для NSView.init (), хотя я вижу, что оно выполняется в отладчике.