Почему эти быстрые подтексты NSView позволяют запустить инициализацию дважды - PullRequest
0 голосов
/ 01 февраля 2019

В подклассах 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 (), хотя я вижу, что оно выполняется в отладчике.

...