代码之家  ›  专栏  ›  技术社区  ›  surfrider

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

  •  3
  • surfrider  · 技术社区  · 6 年前

    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 关键字,代码将不会编译-这是预期的行为,因为扩展中的方法使用静态方法调度->无法重写。 但为什么要加 @对象 让它工作?根据文献和大多数文章,所有这些都是 @对象 dynamic . 但这里似乎没有必要!

    帮我弄明白,为什么 (省略) 动态 )使这些事情成为可能。

    0 回复  |  直到 6 年前
        1
  •  3
  •   Mohmmad S    6 年前

    Extensions ,

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

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

    也看看这个 answer .

    不过,这似乎也是一个支持问题,因为swift编译器只是抛出以下错误:

    覆盖non-@objc 不支持来自扩展的声明。

    苹果称,

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

    但事实并非如此,因为我们正在从扩展中重写,而不是从扩展中重写, extension .

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

    swift编译器vs Objc编译器,

    动态调度与静态调度 .

    苹果也没有官方文件说明为什么swift编译器不支持这个问题,或者他们是否有任何未来的计划来解决这个问题,或者认为这是一个问题。

    However ,不存在快速动态调度;我们只有 只是动态的,你必须写@objc动态的。所以这是有效的 和以前一样,只是说得很清楚。

    article 深入探讨这个话题。