2016-08-10 1 views
1

私は、理想的には彼らのinitsdeinits、内のコードを持っているでしょう2つのクラスを持っている例:複数のinitと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 {} 

しかし、もちろん、私はしていないことができます迅速。私の現在のソリューションは、1プロトコルを作成し、Registryへの呼び出しでinitdeinitを書くために私を思い出させるためにあるノートを入れて、例えばする:

//: 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

は、必要な初期化子を定義します。

protocol Tappable { 
    init(r:Registry) 
} 

その後プロトコルは、あなたがそこに起こるために必要な何を思い出させるだろう期待したいその初期化子を実装する必要があります継承する任意のクラス。

UIViewの指定されたイニシャライザを実装する必要があるUIViewサブクラスでは、特にうまく機能しません。

+0

この提案をお寄せいただきありがとうございます。できる限りアイデアを使用しますが、正確な署名を持つinitを常に持っているとは限りません。アイデアの良い副作用は、依存性注入を強制することです。再度、感謝します。 –

0

2つのスーパークラスを1つのスーパークラスとOptionSetに置き換える別の解決方法があります。明らかに、ケース固有の初期化と初期化解除を多く行う必要がある場合、これはやや難しくなりますが、それはうまく動作します。この例ではです。

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] 
     } 
    } 
} 
+0

ありがとう、私はおそらくこのようなことをすることができます。 –

2

あなたは複合クラスを作成し、変数として、あなたのレジストリクラスを格納することができ、それは次のようになります:、のすべてをdeinitがUIElementオブジェクトで呼び出され

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の形質は登録抹消されます。


スウィフトプレイグラウンドで、以下を追加してテストすることができます。これは、UIElementクラスを作成し、それを特性に登録させてから、それを割り当て解除し、登録を解除します。

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

私はこれを試していただきありがとうございます。 –

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" 
関連する問題