2

我有一個協議叫NakedNavigationBarSwift - 擴展類只有當它符合使用方法調配的協議

我也有一個擴展,擴展所有UIViewController s符合NakedNavigationBar

問題是在擴展中,我想添加默認行爲,以便在初始化UIViewController時,我們使用方法在UIViewController上調整。

這是我的協議和擴展:

import UIKit 


protocol NakedNavigationBar 
{ 

} 

extension NakedNavigationBar where Self: UIViewController 
{ 
    public override class func initialize() 
    { 
     struct Static 
     { 
      static var token: dispatch_once_t = 0 
     } 

     dispatch_once(&Static.token) 
     { 
      let originalSelector = #selector(viewWillAppear(_:)) 
      let swizzledSelector = #selector(nakedNavigationBar_viewWillAppear(_:)) 

      let originalMethod = class_getInstanceMethod(self, originalSelector) 
      let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) 

      let didAddMethod = class_addMethod(self, 
               originalSelector, 
               method_getImplementation(swizzledMethod), 
               method_getTypeEncoding(swizzledMethod)) 

      if didAddMethod 
      { 
       class_replaceMethod(self, 
            swizzledSelector, 
            method_getImplementation(originalMethod), 
            method_getTypeEncoding(originalMethod)) 
      } 
      else 
      { 
       method_exchangeImplementations(originalMethod, swizzledMethod) 
      } 
     } 
    } 


    // MARK: - Swizzling Methods 

    func nakedNavigationBar_viewWillAppear(animated: Bool) 
    { 
     self.nakedNavigationBar_viewWillAppear(animated) 

     print("VWA Swizzling...") 

     // Hide the navigation bar 
     _setNavigationBarVisible(isVisible: false) 
    } 


    // MARK: - 

    private func _setNavigationBarVisible(isVisible isVisible: Bool) 
    { 
     // (Changes background and shadow image) 
    } 
} 

建設時,我得到的錯誤是: errors

本質上告訴我,我不能擴展協議,因爲它不具備UIViewController方法。但據我所知,where Self: UIViewController應該使它只能在UIViewController上工作,只有當視圖控制器符合NakedNavigationBar時才能擴展視圖控制器。

原來延長了extension UIViewController: NakedNavigationBar但是這使得我所有的UIViewController小號瞬間符合NakedNavigationBar而不是隻有我選擇的人。

+0

即使編譯你的方法也行不通。調整方法會影響每個UIViewController,而不僅僅是那些符合你的協議的方法。 – dan

+0

好點:/你能想到解決辦法嗎? –

回答

1

由於SWIFT 3.0,因爲我明白,(語義),你最好想要做的是以下幾點:你想要的是

protocol NakedNavigationBar 
{ 
    //your protocol definition 
} 

extension UIViewController where Self: NakedNavigationBar 
{ 
    //method swizzling and all the goodies 
} 

通知我已經改變了擴展聲明的順序,因爲不是該協議的默認實現,而是該類的默認實現,當該特定子類符合NakedNavigationBar時。問題是,目前這種語法不能編譯!!,我們不能添加Self要求,以一流的擴展 =((我覺得你的痛苦)。

在另一方面,你實際上是試圖做(與Self要求協議擴展)編譯好,但問題是,不能覆蓋一個協議擴展,內部類的方法,並試圖通過調配你:

public override class func initialize() 

添加Self需求時,你可以做什麼到一個協議擴展是調用任何公共API的類(在這種情況下UIViewController)提供,所以你可以做這樣的事情:

protocol NakedNavigationBar 
{ 
    func a() { 
     //define cool stuff... 
    } 
} 

extension NakedNavigationBar where Self: UIViewController 
{ 

    func b() { 
     //invoke stuff from NakedNavigationBar 
     a() 
     //or invoke stuff from UIViewController 
     let viewLoaded = self.isViewLoaded 
    } 
    //but what we CAN'T do are class overrides 
    override class func initialize() {} //---->compilation error 
} 

我希望你能找到的解釋是有用的,我很遺憾地是壞消息,但目前要實現什麼並沒有真正似乎以Swifty類型安全的方式對我可行。

但是不用擔心,生活還在繼續!當我遇到同樣的用例並且像你一樣碰到同一個牆時,我設法讓事情起作用,但它有一個缺點:它不是Swifty類型安全的做事方式(也許我們可以改進這斯威夫特以後的版本,如果它允許在類擴展#fingersCrossed)

簡而言之自我要求,該解決方案是這樣的(使用原來的代碼爲例):

import UIKit 

protocol NakedNavigationBar 
{ 

} 

extension UIViewController //------->simple extension on UIViewController directly 
{ 
    public override class func initialize() 
    { 
     //swizzling stuff switching viewWillAppear(_: Bool) with nakedNavigationBar_viewWillAppear(animated: Bool) 
    } 

    // MARK: - Swizzling Methods 

    func nakedNavigationBar_viewWillAppear(animated: Bool) 
    { 
     self.nakedNavigationBar_viewWillAppear(animated) 

     print("VWA Swizzling...") 

     //------->only run when self conforms to NakedNavigationBar 
     if let protocolConformingSelf = self as? NakedNavigationBar { 
      print("UIViewControllers that conform to NakedNavigationBar, yay!!") 
      //here it's safe to call UIViewController methods OR NakedNavigationBar on protocolConformingSelf instance 
     } 

    } 


    // anything else you want for UIViewController 
} 

缺點:

  • 不是處理服務的「快捷方式」
  • 即使我們只驗證那些符合NakedNavigationBar協議來運行敏感代碼行,也會調用混合方法並在所有UIViewControllers上生效。

我非常希望它有幫助。如果有人發現了另一種(更好的)做法,聽到它真是太棒了!

相關問題