Swift class 的扩展仅当它符合特定协议时
Swift extension of a class ONLY when it conforms to a specific protocol
你好 =) 我刚刚遇到一个设计问题,我需要(基本上)执行以下操作:
我想在 的 viewWillAppear:
上注入一些符合协议 MyProtocol
[=47 的 UIViewController
subclass 的代码=].代码解释:
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension UIViewController where Self: MyProtocol //<-----compilation error
{
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//invoke APIs from
self.protocolFunction() // MyProtocol APIs
let viewLoaded = self.isViewLoaded // UIViewController APIs
}
}
这里的主要问题是我需要在 UIVIewController
扩展中做两件事:
- 同时调用
MyProtocol
和 UIViewController
API 的
- 覆盖
UIViewController
方法 initialize()
以便能够调配 viewWillAppear:
这 2 个功能似乎不兼容(截至 Swift 3)因为:
- 我们无法使用条件 扩展 classes(即
extension UIViewController where Self: MyProtocol
)
- 如果我们 扩展协议 ,我们可以添加条件
extension MyProtocol where Self: UIViewController
但 我们不能覆盖 class 中的方法在协议扩展 中,这意味着我们不能 public override class func initialize()
这是 swizzling 所需要的。
所以我想知道是否有人可以为我面临的这个问题提供 Swifty 解决方案? =)
提前致谢!!
好吧,到目前为止我还没有找到真正令人满意的方法,但我决定 post 我最终为这个特定问题所做的事情。
简而言之,解决方案是这样的(使用原始示例代码):
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension UIViewController //------->simple extension on UIViewController directly
{
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//------->only run when self conforms to MyProtocol
if let protocolConformingSelf = self as? MyProtocol {
//invoke APIs from
protocolConformingSelf.protocolFunction() // MyProtocol APIs
let viewLoaded = protocolConformingSelf.isViewLoaded // UIViewController APIs
}
}
}
缺点:
- 不会"the Swift way"做事
- 调配方法将被调用并对所有
UIViewControllers
生效,即使我们只验证那些符合 MyProtocol
协议的 运行 敏感代码行.
我非常希望它能帮助其他面临类似情况的人 =)
您已接近解决方案。只需要换一种方式。仅当它是 UIViewController 的一部分时才扩展协议。
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension MyProtocol where Self: UIViewController {
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//invoke APIs from
self.protocolFunction() // MyProtocol APIs
let viewLoaded = self.isViewLoaded // UIViewController APIs
}
}
你好 =) 我刚刚遇到一个设计问题,我需要(基本上)执行以下操作:
我想在 的 viewWillAppear:
上注入一些符合协议 MyProtocol
[=47 的 UIViewController
subclass 的代码=].代码解释:
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension UIViewController where Self: MyProtocol //<-----compilation error
{
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//invoke APIs from
self.protocolFunction() // MyProtocol APIs
let viewLoaded = self.isViewLoaded // UIViewController APIs
}
}
这里的主要问题是我需要在 UIVIewController
扩展中做两件事:
- 同时调用
MyProtocol
和UIViewController
API 的 - 覆盖
UIViewController
方法initialize()
以便能够调配viewWillAppear:
这 2 个功能似乎不兼容(截至 Swift 3)因为:
- 我们无法使用条件 扩展 classes(即
extension UIViewController where Self: MyProtocol
) - 如果我们 扩展协议 ,我们可以添加条件
extension MyProtocol where Self: UIViewController
但 我们不能覆盖 class 中的方法在协议扩展 中,这意味着我们不能public override class func initialize()
这是 swizzling 所需要的。
所以我想知道是否有人可以为我面临的这个问题提供 Swifty 解决方案? =)
提前致谢!!
好吧,到目前为止我还没有找到真正令人满意的方法,但我决定 post 我最终为这个特定问题所做的事情。 简而言之,解决方案是这样的(使用原始示例代码):
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension UIViewController //------->simple extension on UIViewController directly
{
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//------->only run when self conforms to MyProtocol
if let protocolConformingSelf = self as? MyProtocol {
//invoke APIs from
protocolConformingSelf.protocolFunction() // MyProtocol APIs
let viewLoaded = protocolConformingSelf.isViewLoaded // UIViewController APIs
}
}
}
缺点:
- 不会"the Swift way"做事
- 调配方法将被调用并对所有
UIViewControllers
生效,即使我们只验证那些符合MyProtocol
协议的 运行 敏感代码行.
我非常希望它能帮助其他面临类似情况的人 =)
您已接近解决方案。只需要换一种方式。仅当它是 UIViewController 的一部分时才扩展协议。
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension MyProtocol where Self: UIViewController {
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//invoke APIs from
self.protocolFunction() // MyProtocol APIs
let viewLoaded = self.isViewLoaded // UIViewController APIs
}
}