覆盖SWIFT扩展中的方法 [英] Overriding methods in Swift extensions

查看:44
本文介绍了覆盖SWIFT扩展中的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我倾向于只将必需品(存储的属性、初始值设定项)放入我的类定义中,而将其他所有内容移到它们自己的extension中,这有点像我也要与// MARK:分组的每个逻辑挡路的extension

例如,对于UIView子类,我最终会得到一个用于布局相关内容的扩展,一个用于订阅和处理事件等的扩展。在这些扩展中,我不可避免地要覆盖一些UIKit方法,例如layoutSubviews。直到今天,我才注意到这种方法有任何问题。

以此类层次结构为例:

public class C: NSObject {
    public func method() { print("C") }
}

public class B: C {
}
extension B {
    override public func method() { print("B") }
}

public class A: B {
}
extension A {
    override public func method() { print("A") }
}

(A() as A).method()
(A() as B).method()
(A() as C).method()

输出为A B C。这对我来说没什么意义。我读到过协议扩展是静态调度的,但这不是协议。这是一个常规类,我希望在运行时动态调度方法调用。显然,C上的调用至少应该动态调度并生成C

如果我从NSObject中删除继承并使C成为根类,编译器会报告说declarations in extensions cannot override yet,这是我已经读过的。但是将NSObject作为根类有什么改变呢?

将两个重写都移动到它们的类声明中会产生A A A,只移动B的会产生A B B,只移动A会产生C B C,最后一个对我来说完全没有意义:即使是静态键入的A也不会再产生A-output!

dynamic关键字添加到定义或重写似乎确实给了我所需的行为,‘从类层次结构中的那个点往下’.

让我们把我们的例子改成结构简单一点的东西,究竟是什么让我发布了这个问题:

public class B: UIView {
}
extension B {
    override public func layoutSubviews() { print("B") }
}

public class A: B {
}
extension A {
    override public func layoutSubviews() { print("A") }
}


(A() as A).layoutSubviews()
(A() as B).layoutSubviews()
(A() as UIView).layoutSubviews()

我们现在得到A B A。在这里,我无法以任何方式将UIView的layoutSubviews动态化。

将这两个重写都移动到它们的类声明中会再次得到A A A,只有A或B仍然会得到A B Adynamic再次解决我的问题。

理论上,我可以将dynamic加到我所做的所有override中,但我觉得在这里我做错了什么。

像我一样使用extension%s对代码进行分组真的错误吗?

推荐答案

扩展不能/不应该重写。

不能按照Apple SWIFT指南中的说明覆盖扩展中的功能(如属性或方法)。

扩展可以向类型添加新功能,但不能覆盖现有功能。

Swift Developer Guide

编译器允许您在扩展中覆盖,以与Objective-C兼容。但它实际上违反了语言指令。

😊刚才让我想起了艾萨克·阿西莫夫的"Three Laws of Robotics"🤖

扩展(语法糖)定义接收自己参数的独立方法。调用的函数(即layoutSubviews)取决于编译代码时编译器知道的上下文。UIView继承自UIResponder,而UIResponder继承自NSObject,因此允许在扩展中重写,但不应重写

所以分组没有什么问题,但是您应该在类中重写,而不是在扩展中重写。

指令说明

如果超类方法是Objective-C兼容的,则您只能在子类的扩展中使用override超类方法,即load()initialize()

因此,我们可以了解它为什么允许您使用layoutSubviews进行编译。

所有SWIFT应用程序都在Objective-C运行时内执行,但使用纯仅SWIFT框架时除外,该框架允许仅使用SWIFT运行时。

我们发现,Objective-C运行库在初始化应用程序进程中的类时,通常会自动调用两个类main方法load()initialize()

关于dynamic修饰符

来自Apple Developer Library(archive.org)

您可以使用dynamic修饰符要求通过Objective-C运行时动态调度对成员的访问。

当Objective-C运行时导入SWIFT API时,不能保证对属性、方法、子脚本或初始值设定项进行动态调度。SWIFT编译器仍可能取消虚拟化或内联成员访问以优化代码性能,从而绕过Objective-C运行时。😳

因此dynamic可以应用于您的layoutSubviews->UIView Class,因为它由Objective-C表示,并且对该成员的访问总是使用Objective-C运行时。

这就是编译器允许您使用overridedynamic的原因。

这篇关于覆盖SWIFT扩展中的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆