什么时候在 Swift 中使用 @objc?

When to use @objc in Swift?

在 Swift 中,我看到一些方法,例如:

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

我想知道什么时候使用@objc?我读了一些文档,但他们说当你希望它在 Objective-C 中可调用时,你应该添加 @objc 标志

然而,这是Swift中的私有函数,@obj是做什么的?

@objc 是一个 class 属性,所以你使用

@objc public class MyClass

它将 class' 方法公开给 Objective C classes,因此只有当 class 包含 public 函数时才可以使用它

private 表示它仅在 Swift 中可见。 所以使用@objc 在 Objective-C 中可见。 如果您有一个函数来选择 swift 中的私有函数,则它是必需的。

The @objc attribute makes your Swift API available in Objective-C and the Objective-C runtime.

参见: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html

@objc / 动态

这是为了兼容性:将 Swift file/code 导入基于 Objective-C 的项目后。

如果您希望 Objective-C 代码或 class 访问您的 property/method,请使用它。

大多数情况下,当您 class 对 Objective-C 基础 class 的 Swift class 进行子 class 时,就会发生这种情况。

A Swift class or protocol must be marked with the @objc attribute to be accessible and usable in Objective-C. This attribute tells the compiler that this piece of Swift code can be accessed from Objective-C. If your Swift class is a descendant of an Objective-C class, the compiler automatically adds the @objc attribute for you.

这里是关于 @objc.

的苹果文档

Using Swift from Objective-C

语言互操作性 兼容性

链接已更新:
看来苹果已更新链接。

一个迟到的答案,但是这个 @objc 行为在 Swift 4 中发生了轻微的变化(它出现在 Xcode 9 中,通常是在 10 天前发布的)。

在Swift4中,删除了@objc的一些推理案例。这仅意味着在某些其他情况下,在 Swift 编译器推断 @objc header 之前,它在 Swift 4 中未被推断。

阅读有关 this change

的 Swift 进化提案的更多信息

如前所述,通常 @objc 是将某些方法公开给 Objective-C 运行时,这是 Swift 语言互操作性的一部分。

另一个迟到的答案,但是 none 这个问题的现有答案确实回答了 OP 的问题,即:为什么你需要在 [=13= 上使用 @objc ] class 成员,如果 @objc 是为了与 Objective-C 交互,并且该成员是私有的,这意味着即使您的项目中有 Objective-C 代码,它反正也见不到会员了?

原因在于,由于许多框架都是用 Objective-C 编写的,因此有时需要 Objective-C 功能才能与某些 API 进行交互。

例如,假设我想通过 DistributedNotificationCenter:

注册一个通知
DistributedNotificationCenter.default.addObserver(self,
                                                  selector: #selector(somethingHappened(_:)),
                                                  name: someNotification,
                                                  object: nil)

为此,我们需要能够获取 somethingHappened 方法的选择器。但是,选择器是一个 Objective-C 概念,因此如果该方法对 Objective-C 不可见,则它没有选择器。因此,即使该方法是私有的并且不应被任意外部代码调用,它也需要一个 @objc 才能使 Objective-C 中编写的 DistributedNotification 代码成为能够通过其选择器调用它。

另一个需要@objc的常见情况是支持键值编码(KVC),特别是在macOS上,KVC和KVO用于实现Cocoa绑定。与 Cocoa 中的许多其他系统一样,KVC 在 Objective-C 中实现,其效果是要求将符合 KVC 的属性公开给 Objective-C 运行时。有时,将符合 KVC 的属性设置为私有是有意义的。一个例子是当你有一个影响其他属性的 属性 时:

@objc private dynamic var originalProperty: String

@objc private static let keyPathsForValuesAffectingDependentProperty: Set<String> = [
    #keyPath(originalProperty)
]
@objc public var dependentProperty: String { return changeItSomehow(self.originalProperty) }

在这种情况下,我们实际存储的 属性 是私有的,但是我们 暴露给外部代码的依赖 属性 需要发送更新私人 属性 时的通知。通过将私有 属性 标记为 @objc,我们可以通过设置 KVC 依赖项轻松地做到这一点——否则,我们必须编写代码来手动发送私有 属性 中的通知的 willSetdidSet 处理程序。另外,通知KVC系统dependentProperty依赖originalProperty的静态属性需要暴露给Objective-C,以便KVC系统找到并调用它, 但它与我们代码的客户无关。

此外,macOS 应用程序中的视图控制器使用 Cocoa 绑定作为实现细节更新其视图中的控件可能会使某些私有属性符合 KVC,以便将这些控件绑定到它们。

因此,如您所见,有时可能需要向 Objective-C 公开方法或 属性 以便与框架交互,而不必对框架的客户可见你的代码。

@objc 对比@objcMembers

@objcObjective-C runtime. Let's take a look at #selector[About] feature of Swift to use an Objective-C runtime. In this case you are able to define your Swift @objc private func

公开声明

要使用 Swift 来自 Objective-C 的功能:

  1. Swift的class应该从NSObject
  2. 扩展
  3. 标记Swift的:

一个。仅 @objcMembers class - 公开 all public constructors领域方法。也适用于 subclasses

b。 @objcclass/enum/protocol结构除外)[Named Type]

  • @objc class(可选)- 公开一个 default public init()。或 @objc(<custom_name>) 为 class.
  • 设置自定义名称
  • @objc 构造函数字段方法 - 有选择地公开它们

Swift的方法将在下一个命名时可用:

<swiftName>With<firstArgument>:<secondArgument>:

例如:

public func printHelloWorld(arg1: String, arg2:String)
//is reached through: 
[someObject printHelloWorldWithArg1: arg2:];