Ada*_*ter 3 uiviewcontroller ios swift swift-extensions method-swizzling
我有一个名为 的协议NakedNavigationBar。
我还有一个扩展,可以扩展所有UIViewController符合NakedNavigationBar.
问题是,在扩展中我想添加默认行为,以便在初始化时UIViewController,我们在UIViewController.
这是我的协议和扩展:
\n\nimport UIKit\n\n\nprotocol NakedNavigationBar\n{\n\n}\n\nextension NakedNavigationBar where Self: UIViewController\n{\n public override class func initialize()\n {\n struct Static\n {\n static var token: dispatch_once_t = 0\n }\n\n dispatch_once(&Static.token)\n {\n let originalSelector = #selector(viewWillAppear(_:))\n let swizzledSelector = #selector(nakedNavigationBar_viewWillAppear(_:))\n\n let originalMethod = class_getInstanceMethod(self, originalSelector)\n let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)\n\n let didAddMethod = class_addMethod(self,\n originalSelector,\n method_getImplementation(swizzledMethod),\n method_getTypeEncoding(swizzledMethod))\n\n if didAddMethod\n {\n class_replaceMethod(self,\n swizzledSelector,\n method_getImplementation(originalMethod),\n method_getTypeEncoding(originalMethod))\n }\n else\n {\n method_exchangeImplementations(originalMethod, swizzledMethod)\n }\n }\n }\n\n\n // MARK: - Swizzling Methods\n\n func nakedNavigationBar_viewWillAppear(animated: Bool)\n {\n self.nakedNavigationBar_viewWillAppear(animated)\n\n print("VWA Swizzling...")\n\n // Hide the navigation bar\n _setNavigationBarVisible(isVisible: false)\n }\n\n\n // MARK: -\n\n private func _setNavigationBarVisible(isVisible isVisible: Bool)\n {\n // (Changes background and shadow image)\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n本质上告诉我,我无法扩展协议,因为它没有\xe2\x80\x99t 的方法UIViewController。但据我了解,where Self: UIViewController应该使其仅适用于UIViewController,仅当它符合 时才扩展视图控制器NakedNavigationBar。
最初的扩展是extension UIViewController: NakedNavigationBar,但这使得我的所有UIViewControllers 立即符合NakedNavigationBar而不仅仅是我选择的。
据我了解,从 swift 3.0 开始,(从语义上讲)您理想想要做的事情如下:
protocol NakedNavigationBar
{
//your protocol definition
}
extension UIViewController where Self: NakedNavigationBar
{
//method swizzling and all the goodies
}
Run Code Online (Sandbox Code Playgroud)
请注意,我更改了扩展声明的顺序,因为您想要的不是协议的默认实现,而是UIViewController当特定子类符合NakedNavigationBar. 问题是,目前该语法无法编译!!,我们无法Self向类扩展添加要求=((我感受到你的痛苦)。
另一方面,您实际尝试做的事情(具有Self要求的协议扩展)编译得很好,但问题是您无法覆盖协议扩展中的类方法,并且无法尝试混淆您:
public override class func initialize()
Run Code Online (Sandbox Code Playgroud)
当向协议扩展添加需求时,您可以做的Self是调用该类(在本例中UIViewController)提供的任何公共 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
}
Run Code Online (Sandbox Code Playgroud)
我希望你觉得这个解释有用,很抱歉给你带来坏消息,但目前你想要实现的目标对我来说似乎并不能以 Swifty 类型安全的方式实现。
但不用担心!生活还要继续!当我遇到与你相同的用例并遇到同样的困难时,我设法让事情正常工作,但它有一个缺点:这不是 Swifty 类型安全的做事方式(也许我们可以改进如果 Swift 的后续版本允许对类扩展的自我要求,则会出现这种情况#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
}
Run Code Online (Sandbox Code Playgroud)
缺点:
UIViewControllers,即使我们只验证那些符合NakedNavigationBar协议来运行敏感代码行的方法。我非常希望它有帮助。如果有人找到另一种(更好的)方法,很高兴听到它!
| 归档时间: |
|
| 查看次数: |
1108 次 |
| 最近记录: |