2016-06-28 1 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} '의 설정 기능을 강제해야합니까? 그렇지 않으면 기본 속성 구현을위한 빈 setter가 있어야합니다. 나는 속성을'{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 
    } 
} 

클라이언트 클래스 :

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) 
     } 
    } 
} 
관련 문제