何时在 Swift 中使用 @objc?

Posted

技术标签:

【中文标题】何时在 Swift 中使用 @objc?【英文标题】:When to use @objc in Swift? 【发布时间】:2015-08-27 23:51:45 【问题描述】:

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

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

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

不过,这是 Swift 中的私有函数,@obj 有什么作用?

【问题讨论】:

好问题!!! 【参考方案1】:

private 意味着它只在 Swift 中可见。 所以使用@objc 在Objective-C 中可见。 如果你有一个函数可以在 swift 中选择一个私有函数,它是必需的。

@objc 属性使您的 Swift API 在 Objective-C 和 Objective-C 运行时中可用。

见: 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 private func doubleTapGestureRecognized,同时拥有@objc 和私有有什么意义?你是说 Objective-C 类可以覆盖 doubleTapGestureRecognized 吗? 我猜,因为在 obj-c 中你可以覆盖任何方法。 不确定这个答案是否正确并回答了他的 Q。这里提供的答案已经在他的 Q 中“但是他们说当你希望它在 Objective-C 中可以调用时,你应该添加\@objc flag" ,他的主要Q是"这是swift中的一个私有函数,\@obj是做什么的?" 链接中断。特别是在 Apple 文档中。请考虑从此处的文档中提取关键元素。【参考方案2】:

另一个迟到的答案,但这个问题的现有答案都没有真正回答 OP 的问题,即:如果有 @objc,为什么你需要在 private 类成员上使用 @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 以便与框架交互,而不必对代码的客户端可见。

【讨论】:

谢谢。这是一个很好的答案,直接解决了这个问题。【参考方案3】:

@objc / 动态

这是为了兼容性:将 Swift 文件/代码导入基于 Objective-C 的项目后。

如果您希望 Objective-C 代码或类访问您的属性/方法,请使用它。

大多数情况下,它发生在您对 Objective-C 基类的 Swift 类进行子类化时。

必须用 @objc 属性标记 Swift 类或协议 在 Objective-C 中可以访问和使用。这个属性告诉 可以从中访问这段 Swift 代码的编译器 目标-C。如果你的 Swift 类是 Objective-C 的后代 类,编译器会自动为你添加@objc属性。

这里是关于 @objc 的苹果文档。

Using Swift from Objective-C

Language Interoperability Compatibility

链接已更新:链接似乎已被苹果更新。

【讨论】:

【参考方案4】:

@objc 是类属性,所以你使用

@objc public class MyClass

它将类的方法暴露给 Objective C 类,所以只有当你的类包含公共函数时你才会使用它

【讨论】:

【参考方案5】:

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

在 Swift 4 中,删除了一些 @objc 的推理案例。这只是意味着在某些其他情况下,在 Swift 编译器推断出 @objc 标头之前,它在 Swift 4 中没有推断出来。

阅读更多关于this change的Swift进化提案

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

【讨论】:

所以这应该是为什么在更新到 Swift 4 之后某些变量无法从 ObjC 访问的原因吧?使用 Swift 3.X 无需添加 @objc 哦,好的,与其他人仔细检查总是好的,谢谢!【参考方案6】:

@objc 与 @objcMembers

@objcObjective-C runtime[About] 公开声明。让我们看看#selector[About] Swift 使用 Objective-C 运行时的特性。在这种情况下,您可以定义您的 Swift @objc private func[More]

在 Objective-C 中使用 Swift 的函数:

    Swift 的类应该从 NSObject 扩展 马克·斯威夫特:

一个。 @objcMembers class 仅 - 公开 all public constructorsfieldsmethods强>。也适用于子类

b. @objcclass/enum/protocolstruct除外)[Named Type]

@objc class(可选)- 公开 默认 public init()。或@objc(&lt;custom_name&gt;) 为类设置自定义名称。 @objc 构造函数字段方法 - 有选择地公开它们

Swift 的方法将通过下一个命名提供:

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

例如:

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

[@objc and dynamic]

【讨论】:

以上是关于何时在 Swift 中使用 @objc?的主要内容,如果未能解决你的问题,请参考以下文章

用 Swift 中使用的 ObjC 编写的消除歧义覆盖方法

在ObjC中使用Swift库

在 Swift 中使用带有 UnsafeMutableRawPointer 或 UnsafeMutablePointer 参数的 ObjC 函数?

没有 objc 的协议中的 Swift 可选方法

如何避免在带有 Swift 4 的 iOS 11 中使用带有刷新控件的 @objc?

如果类没有以 `@objc` 为前缀,是不是可以在 Objective-C 项目中使用用 Swift 编写的 pod?