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上生效。

我非常希望它有帮助。如果有人发现了另一种(更好的)做法,听到它真是太棒了!

相关问题