我有两个类,理想情况下会在inits
和deinits
中包含代码,例如:
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 {}
但当然我不能在斯威夫特。我目前的解决方案是制作一个协议并添加一个注释,提醒我写init
和deinit
来调用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) }
}
有更好的方法吗?
答案 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"