用'@objc'属性覆盖的扩展方法背后的机制是什么?

时间:2019-02-24 13:40:44

标签: swift

书呆子问题的种类。对我来说还不清楚,究竟是什么使该代码起作用:

class Shape { }

extension Shape {
    @objc func redraw() {
        print("from ext")
    }
}

class Circle: Shape { }

class Line: Shape {
    override func redraw() { // Compiler error: Declarations from extensions cannot be overridden yet
        print("from subclass")
    }
}

let line = Line()
let shape:Shape = line
let circle = Circle()

line.redraw() //from subclass
circle.redraw() //from ext
shape.redraw() //from subclass

如果我省略扩展名中的@objc关键字,则代码将无法编译-这是预期行为,因为扩展名中的方法使用静态方法分派->无法覆盖。 但是为什么要添加@objc使其起作用呢?根据文档和大多数文章的介绍,@objc的全部工作是使事物对Objective-c运行时可见。要更改方法分派类型,有一个特殊的关键字-dynamic。但似乎这里没有必要!

帮我弄清楚,为什么添加@objc(并省略dynamic)使这种事情成为可能。

1 个答案:

答案 0 :(得分:3)

Extensions

  顾名思义,

应该是扩展/添加/包含方法   到现有的实现中,使它们成为最漂亮的之一   关于Objective-C,现在是Swift,因为您可以将代码添加到   您不拥有的类或框架。因此,有道理   从概念上讲,您不应该在扩展程序中“替换”代码   说话。

这就是为什么编译器在尝试这样做时会抱怨的原因。

也请查看此answer

但是这似乎也是一个支持问题,因为快速编译器只会抛出此错误:

  

不支持从扩展名覆盖非@objc声明。

根据苹果公司

  

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

事实并非如此,因为我们从扩展名中覆盖,反之亦然, 这使我们回到了extension的声明。

  

扩展将新功能添加到现有的类,结构,枚举或协议类型。这包括扩展您无法访问原始源代码的类型的能力(称为追溯建模)。扩展与Objective-C中的类别相似。 (与Objective-C类别不同,Swift扩展名没有名称。)Here

回到旧主题 swift编译器与Objc编译器

动态分配与静态分配

而且,苹果公司也没有官方文件说明为什么Swift编译器不支持此功能,或者他们是否有未来的计划来解决此问题或将其视为根本问题。

  

However,没有诸如Swift动态调度之类的东西;我们只有   Objective-C运行时的动态分配。这意味着你不能   只是动态的,您必须编写@objc动态的。所以这是有效的   与以前相同的情况,只是明确了。

下面是一个很棒的article,深入讨论了这个话题。