2

私はNakedNavigationBarというプロトコルを持っています。Swift - メソッドスウィズリングを使用するプロトコルに準拠している場合にのみクラスを拡張する

NakedNavigationBarに準拠するUIViewControllerのすべてを拡張する拡張子もあります。

拡張機能では、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: UIViewControllerUIViewControllerでのみ動作し、ビューコントローラは NakedNavigationBarに適合する場合にのみ拡張するようにしてください。

はもともと拡張でしたextension UIViewController: NakedNavigationBarが、これは私のUIViewController秒のすべてが瞬時にNakedNavigationBarではなく、私が選択したものだけに準拠します。 3.0 SWIFTのよう

+0

あなたのアプローチをコンパイルしてもうまくいかない場合でも。メソッドをスウィズルすることは、あなたのプロトコルに準拠したものだけでなく、すべての 'UIViewController'に影響します。 – dan

+0

良い点:/あなたは仕事を考えていますか? –

答えて

1

私はあなたが理想的にやりたい(意味的に)何が以下であることを理解して:あなたは何をしたいがあるので、私は、拡張宣言の順序を変更した

protocol NakedNavigationBar 
{ 
    //your protocol definition 
} 

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

お知らせプロトコルのデフォルトの実装ではなく、特定のサブクラスがNakedNavigationBarに準拠するとき、UIViewControllerクラスのデフォルト実装です。事は、我々は、クラスの拡張 =((私はあなたの痛みを感じる)にSelf要件を追加することはできません、現在その構文は!!コンパイルされません、である。

一方、あなたが実際にやってみました何( Self要件とプロトコル拡張は)うまくコンパイルが、問題は、あなたがプロトコル拡張、内部クラスのメソッドをオーバーライドすることはできませんということであり、あなたをスウィズルしようとすることによって:

public override class func initialize() 

Self要件を追加するとき、あなたは何ができるのかプロトコル拡張は、クラスのいずれかの公開APIを呼び出すことです(この場合は

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 
} 

私はあなたが説明が役に立つことを願って、私は悪いニュースの無記名であることが残念ですが、現在あなたが達成したいのか、本当にいないようです:UIViewController)はあなたのようなことを行うことができますので、提供しています私にはSwiftyタイプセーフな方法で実行可能です。

しかし、心配しない!、人生が続く!同じユースケースに遭遇して同じ壁に当たったとき、私は物事を働かせることができましたが、ちょっとした欠点があります。それは、Swiftyタイプセーフな方法ではありません。

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 
} 

欠点:これは、クラスの拡張#fingersCrossed)一言で言えば

上の自己の要求を可能にしている場合スウィフトの今後のリリースでは、溶液は、一例として、あなたの元のコード)を使用して、(このように書きます:

  • もの
  • をすることのない "スウィフト道"
  • NakedNavigationBarプロトコルに準拠しているコードだけを検証して、機密コード行を実行するようにしても、スウィズルメソッドが呼び出され、ALL UIViewControllersに適用されます。

非常に助かります。誰かがそれをやっている別の(より良い)方法を見つけたなら、それを聞いてうれしいでしょう!

関連する問題