2016-06-28 16 views
1

setInteractionEnabledメソッドが別のクラス(例:ネットワーク状態マネージャ)から呼び出されたときにUIViewControllerのインターフェイスを調整する機能を装飾したいと思います。すべての変更(ある場合)は、onInteractionChangedを上書きしてコンクリートコントローラに提供する必要があります。ここに私のコードは次のとおりです。プロトコル拡張のスウィフトクロージャ

import Foundation 

typealias InteractionClosure = ((enabled: Bool) -> Void) 

protocol Interaction: class { 

    var onInteractionChanged: InteractionClosure? { get set } 

    func setInteractionEnabled(enabled: Bool) 

} 

extension Interaction where Self: UIViewController { 

    // Default: Do nothing 
    // Throws: - Extensions may not contain stored properties 
    var onInteractionChanged: InteractionClosure? = nil 

    func setInteractionEnabled(enabled: Bool) { 
     onInteractionChanged?(enabled: enabled) 
    } 

} 

extension UIViewController : Interaction {} 

onInteractionChangedのデフォルトの実装を追加する方法は?自分の質問に答える

+1

エラーには、すべての拡張機能に格納されたプロパティを含めることはできないというエラーが表示されます。アクセスすると 'nil'を返す計算されたプロパティにする必要があります。プロトコルはプロパティ '{get set} 'の設定を強制する必要がありますか?それ以外の場合は、デフォルトのプロパティ実装用の空のセッターを用意する必要があります。私はプロパティを '{get}'にし、適合した型に計算されたプロパティ(getのみ)を単にオーバーライドするのか、ストアドプロパティ(gettableとsettable)を使うのかを選択できます。 – Hamish

答えて

4

通常、私はしていないものですが、ここに私のソリューションです:

typealias InteractionClosure = (enabled: Bool) -> Void 

protocol Interaction: class { 

    func addOnInteractionChanged(closure: InteractionClosure) 
    func setInteractionEnabled(enabled: Bool) 

} 

extension Interaction where Self: UIViewController { 

    func addOnInteractionChanged(closure: InteractionClosure) { 
     onInteractionChanged = closure 
    } 

    func setInteractionEnabled(enabled: Bool) { 
     onInteractionChanged?(enabled: enabled) 
    } 

    // MARK: - Private 

    private var onInteractionChanged: InteractionClosure? { 
     get { 
      let wrapper = 
       objc_getAssociatedObject(self, &icAssociationKey) as? ClosureWrapper 
      return wrapper?.closure 
     } 
     set(newValue) { 
      objc_setAssociatedObject(self, 
            &icAssociationKey, 
            ClosureWrapper(newValue), 
            .OBJC_ASSOCIATION_RETAIN) 
     } 
    } 

} 

extension UIViewController : Interaction {} 

// Helpers 

private var icAssociationKey: UInt8 = 0 

private class ClosureWrapper { 
    var closure: InteractionClosure? 

    init(_ closure: InteractionClosure?) { 
     self.closure = closure 
    } 
} 

Clientクラス:

visibleViewController?.setInteractionEnabled(true) 
+0

解決策は魅力のようです。しかし、私は 'icAssociationKey'で混乱しています。なぜicAssociationKeyが必要なのか?もし私がそれを削除するか? –

0
:マネージャクラスで

class LoginViewController: UIViewController { 

    // MARK: - Lifecycle 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.setup() 
    } 

    // MARK: - Private 

    private func setup() { 
     // ... 

     addOnInteractionChanged { [unowned self] (enabled) in    
      self.signInButton.enabled = enabled 
      self.activityIndicatorView.hidden = !enabled 
     } 
    } 

} 

プロパティに{ get }能力しか持たせたくない場合は、

protocol TestProtocol { 
    var testClosure: ((_ parameter: Bool) -> Void)? { get } 
} 

extension TestProtocol { 
    var testClosure: ((_ parameter: Bool) -> Void)? { 
     return { parameter in 
      print(parameter) 
     } 
    } 
} 
関連する問題