Swift本机基类或NSObject


105

我测试了一些用Swift 编写的isa,发现它仅在NSObject是超类(直接或更高级)或使用'@objc'装饰时才有效。否则,它将遵循静态和vtable-dispatch样式,例如C ++。

定义没有Cocoa / NSObject基类的Swift类是否正常?如果我担心的话,这意味着要放弃Objective-C的许多活力,例如方法拦截和运行时自省。

动态运行时行为位于属性观察器,核心数据,面向方面的编程高阶消息传递,分析和日志记录框架等功能的核心。

使用Objective-C的方法调用样式会将大约20个机器代码操作数添加到方法调用中,因此在某些情况下(对带有小实体的方法进行许多紧密调用),C ++样式的静态和vtable分派可以更好地执行。

但是考虑到一般的95-5规则(95%的性能提升来自调整5%的代码),从强大的动态功能入手并在必要时进行强化是否有意义?


相关:Swift是否支持面向方面的编程?stackoverflow.com/a/24137487/404201
贾斯珀·布鲁斯

Answers:


109

Swift类是NSObject的子类:

  • 本身就是Objective-C类
  • 使用objc_msgSend()的调用(大部分)的方法
  • 提供(大多数)方法实现的Objective-C运行时元数据

不是NSObject子类的Swift类:

  • 是Objective-C类,但仅实现了少数几种方法以实现NSObject兼容性
  • objc_msgSend()用于对其方法的调用(默认情况下)
  • 不为其方法实现提供Objective-C运行时元数据(默认情况下)

在Swift中对NSObject进行子类化可以为您带来Objective-C运行时的灵活性,同时也为您带来Objective-C的性能。如果不需要Objective-C的灵活性,避免使用NSObject可以提高性能。

编辑:

在Xcode 6 beta 6中,将显示动态属性。这使我们可以指示Swift一个方法应使用动态调度,并因此支持拦截。

public dynamic func foobar() -> AnyObject {
}

1
Swift使用哪种调度而不是objc_msgSend?它是静态的吗?
比尔

12
Swift可以使用objc_msgSend派发,虚拟表派发,直接派发或内联。
格雷格·帕克

静态:小于1.1ns。vtable 1.1ns,msgSend 4.9ns。。(当然取决于硬件)。。看起来“纯净的” Swift对于系统级编程来说是一种很棒的语言,但是对于应用程序,我不愿意放弃动态功能,尽管我很高兴将它们转移到Garbage Collection vs ARC中。。。我听说它说静态调度可以在多核系统上实现更好的分支预测(从而提高性能)。真正?
Jasper Blues 2015年

“不是NSObject子类的Swift类是Objective-C类”-您可以提供指向所声明内容的链接吗?
Matt S.

1
因此总之,如果我需要与Objective C代码进行通信,我应该只在Swift中子类化NSObject吗?
MobileMon

14

我还发现,如果将Swift类基于NSObject,则会看到一些意外的运行时行为,该行为可能会隐藏编码错误。这是一个例子。

在此示例中,在我们基于NSObject的情况下,编译器正确地在testIncorrect_CompilerShouldSpot中发现了错误,并报告“ ...'MyClass'无法转换为'MirrorDisposition'”

class MyClass {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

在此示例中,我们基于NSObject,编译器在testIncorrect_CompilerShouldSpot中发现错误:

class myClass : NSObject {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

我想这是道德的,仅基于您真正必须使用的NSObject!


1
谢谢(你的)信息。
贾斯珀·布鲁斯

13

根据语言参考,不需要类继承任何标准根类,因此您可以根据需要包含或忽略超类。

请注意,从类声明中省略超类并不会分配任何隐式基础超类。它定义了一个基类,它将有效地成为独立类层次结构的根。

从语言参考:

Swift类不能从通用基类继承。您未指定超类而定义的类将自动成为基础类供您构建。

尝试super从没有超类(即基类)的类进行引用将导致编译时错误

'super' members cannot be referenced in a root class

1
是的 如果尝试在项目的上下文中创建Cocoa或Cocoa Touch源文件,则插入子类的形式实际上会阻止您创建类,而将其保留为空白。创建超类后,您可以在以后删除它。
Cezar 2014年

1
谢谢。使用静态和vtable分派对于系统编程或性能调整很有意义。为了与本地可可粉保持一致,我认为动态应该是默认设置。(除非有人可以说服我否则,这个问题)。
贾斯珀·布鲁斯

1

我相信绝大多数Swift数据都不会objc。这样,只有那些确实需要与Objective C基础结构进行通信的部分才会被明确标记。

我不知道在多大程度上将运行时自省添加到语言中。只有在方法明确允许的情况下,方法拦截才有可能实现。这是我的猜测,但是只有Apple内部的语言设计师才真正知道他们的前进方向。


对我而言,将动态默认设置(通过扩展NSObject,使用'@objc'装饰或其他方法)是有道理的。似乎在没有基类的情况下,Swift会偏爱静态/ vtable调度,这种方法性能更好,但是在大多数情况下,这不是必需的。。(90%的收益来自调整10%的代码)。我希望与Objective-C的动态性保持一致,而不是选择加入。
Jasper Blues 2014年

语言的设计方式是可选的。据我们所知,很可能将来会添加非本地objc的系统API。从中期/长期来看,他们甚至可以将现有库迁移到具有objc中的瘦兼容性层的非objc代码,该薄层可调用非objc代码。我们只是不知道。educated guesses从现在起几年后,我们可能就能实现。但是目前,这只是一个很大的问号。
Analog File

@JasperBlues我认为大多数时候不需要动态,我宁愿默认情况下具有性能,然后选择动态行为。我猜对每个人来说都是:)
Lance

@Lance Hmmmm。也许。我仍然关注:观察者,AOP,测试模拟框架,分析框架等。而性能是90%的增益来自调整10%。。因此,这就是我的理由-选择加入这10%的案例。我认为AOP对于iOS企业应用程序来说意义重大,但可以使用C ++中的编译器工具来完成。。当然,游戏,科学计算,图形等开发人员将欢迎更多的性能:)
Jasper Blues


-6

这是正常的。看一下Swift的设计目标:目标是使大量的编程问题消失。方法混乱可能不是您要使用Swift要做的事情之一。


3
方法混乱是一种在运行时实现拦截模式的方法。用途之一是根据面向方面编程的原则应用跨领域关注点。苹果自己的通知,属性观察器(内置于swift中),核心数据均使用swizzling效果良好。。尽管它的语法笨拙,但它吸引了人们对Objective-C的一件事是这种动态性,这使得在需要拦截模式时很容易提供优雅的解决方案。。实际上,没有针对Objc的正式AOP框架,因为原材料是如此之好。
贾斯珀·布鲁斯

现在就是这样做的事实,并不意味着明天就会这样做。如您所说,通知是由本机提供的,也可以是本机提供的。语言会发展,我们不知道朝哪个方向发展。在对函数式编程的支持方面,它获得了很多好处。但这是以一种不寻常的方式进行的,因此我不知道还有多少缺失。但是据我们所知,它们可能正在朝着阻止突变和鼓励纯函数式编程的方向发展。如果UI的未来是被动的怎么办?还没有办法知道。
Analog File

1
是的,但是所有这些都取决于侦听,侦听可以通过两种方式完成:编译时(C ++)或运行时(Ruby,Objective-C,Java(通过asm,cglib,ApsectJ等))。现代语言倾向于在运行时执行此操作。人们喜欢Objective-C,因为尽管它是老字号,但它的表现却像现代语言一样。就像您说的那样,语言中包含的内容越多越好(只要做得好!)。。但是现在我们可以借鉴Objc / Foundation提供的遗产,这就是为什么我希望扩展NSObject成为未来几年日常应用程序的标准做法。
贾斯珀·布鲁斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.