Swift最佳实践是多次继承inits和deinits?

时间:2016-08-10 00:54:06

标签: swift protocols multiple-inheritance

我有两个类,理想情况下会在initsdeinits中包含代码,例如:

class Tappable {
    init() { Registry.register(tappable: self) }
    deinit { Registry.deregister(tappable: self) }
}
class Resizable {
    init() { Registry.register(resizable: self) }
    deinit { Registry.deregister(resizable: self) }
}

理想情况下,我会继承两者,例如:

class UIElement: Tappable, Resizable {}

但当然我不能在斯威夫特。我目前的解决方案是制作一个协议并添加一个注释,提醒我写initdeinit来调用Registry,例如:

//: Classes that implememt `Resizable` must call `Registry.register(resizable: self)` in all `init`s and have `deinit { Registry.deregister(resizable: self) }`.
protocol Resizable {}
class UIElement: Tappable, Resizable {
    override init() {
        super.init()
        Registry.register(resizable: self)
    }
    deinit { Registry.deregister(resizable: self) }
}

有更好的方法吗?

4 个答案:

答案 0 :(得分:3)

您可以创建一个复合类并将您的Registry类存储为变量,它可能如下所示:

protocol Register {
    init(_ target: UIElement)
    func deregister(target: UIElement)
}
class Tappable: Register {
    required init(_ target: UIElement) { Registry.register(tappable: target) }
    func deregister(target: UIElement) { Registry.deregister(tappable: target) }
}
class Resizable: Register {
    required init(_ target: UIElement) { Registry.register(resizable: target) }
    func deregister(target: UIElement) { Registry.deregister(resizable: target) }
}

class UIElement {
    var traits: [Register]!
    override init() {
        self.traits = [Tappable(self), Resizable(self)]
    }
    deinit {
        self.traits.forEach { $0.deregister(self) }
    }
}

这样,当在UIElement对象上调用deinit时,UIElement的所有特征都将被取消注册。

您可以在Swift Playground中通过在底部添加以下内容来测试它。这将创建UIElement类,让它注册特征,然后取消分配它并取消注册!

var test: UIElement! = UIElement()
test = nil

答案 1 :(得分:0)

您可以让每个协议定义所需的初始化程序:

protocol Tappable {
    init(r:Registry)
}

然后,任何继承协议的类都必须实现该初始化程序,您希望它会提醒您需要在那里发生什么。

对于需要实现UIView指定初始值设定项的UIView子类来说,这并不是特别有效。

答案 2 :(得分:0)

这是另一个解决方案,它用一个超类和一个OptionSet替换你的两个超类。显然,如果您需要进行大量特定于案例的初始化和去初始化,这会有点笨拙,但对于给出的示例,它可以 okay

class Registry {
    class func register(resizeable: Any) {

    }
    class func register(tappable: Any) {

    }
}

struct ViewTraits: OptionSet {
    let rawValue: Int
    init(rawValue: Int) { self.rawValue = rawValue }
    static let Tappable = ViewTraits(rawValue: 1)
    static let Resizeable = ViewTraits(rawValue: 2)
}

protocol Traits {
    var traits:ViewTraits { get }
}

class TraitedView: NSView, Traits {
    var traits:ViewTraits {
        get {
            fatalError("Must implement a getter for Traits")
        }
    }
    private func register() {
        if (traits.contains(.Tappable)) {
            Registry.register(tappable: self)
        }
        if (traits.contains(.Resizeable)) {
            Registry.register(resizeable: self)
        }
    }
    override init(frame:NSRect) {
        super.init(frame: frame)
        register()
    }

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

class MyView: TraitedView {
    override var traits: ViewTraits {
        get {
            return [ViewTraits.Resizeable, ViewTraits.Tappable]
        }
    }
}

答案 3 :(得分:0)

我在下面的操场上捏造了每个人的想法。感谢。

var sequence = ""
enum Registry {
    static func register(tappable _: Tappable) { sequence += "reg. tap.\n" }
    static func deregister(tappable _: Tappable) { sequence += "dereg. tap.\n" }
    static func register(resizable _: Resizable) { sequence += "reg. res.\n" }
    static func deregister(resizable _: Resizable) { sequence += "dereg. res.\n" }
}
class Registrar {
    init() {
        if let tappable = self as? Tappable {
            Registry.register(tappable: tappable)
        }
        if let resizable = self as? Resizable {
            Registry.register(resizable: resizable)
        }
    }
    deinit {
        if let tappable = self as? Tappable {
            Registry.deregister(tappable: tappable)
        }
        if let resizable = self as? Resizable {
            Registry.deregister(resizable: resizable)
        }
    }
}
protocol Tappable {
    func tap()
}
extension Tappable {
    func tap() { sequence += "tap\n" }
}
protocol Resizable {
    func resize()
}
extension Resizable {
    func resize() { sequence += "resize\n" }
}
class UIElement: Registrar, Tappable, Resizable {
}
var uie: UIElement! = UIElement()
uie.tap()
uie.resize()
uie = nil
sequence // "reg. tap.\nreg. res.\ntap\nresize\ndereg. tap.\ndereg. res.\n"