2016-06-28 33 views
1

我想裝飾UIViewController,當從另一個類(例如網絡狀態管理器)調用setInteractionEnabled方法時,能夠調整它的界面。應通過覆蓋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}」的設置能力嗎?否則,您必須爲默認屬性實現設置一個空setter。我會讓該屬性成爲一個'{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類:

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 
     } 
    } 

} 

Manager類:

visibleViewController?.setInteractionEnabled(true) 
+0

解決方案就像魅力一樣工作。但我在'icAssociationKey'混淆了。爲什麼需要'icAssociationKey'。如果我刪除它呢? –

0

如果你想要財產只有{ get }的能力,你可以使用:

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

extension TestProtocol { 
    var testClosure: ((_ parameter: Bool) -> Void)? { 
     return { parameter in 
      print(parameter) 
     } 
    } 
}