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


87

在Swift中,我看到一些类似的方法:

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

我想知道何时使用@objc?我读了一些文档,但他们说要在Objective-C中调用它时,应添加@objc标志

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


1
好问题!
Erhan Demirci,

Answers:


66

private表示仅在Swift中可见。因此使用@objc在Objective-C中可见。如果您有功能可以快速选择私有功能,则必须使用该功能。

@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


1
因此@objc private func doubleTapGestureRecognized,同时拥有@objc和private的意义何在?您是说Objective-C类可以覆盖doubleTapGestureRecognized吗?
Wingzero 2015年

1
我猜是因为在obj-c中您仍然可以覆盖任何方法。
奇怪的时候2015年

2
不确定这个答案是否正确并回答他的Q。这里提供的ans已经在他的Q本身中了,“但是他们说,当您希望它可以在Objective-C中被调用时,您应该添加\ @objc标志”,他的主要问:“这是迅速的私有函数,\ @ obj可以做什么?”
KBJ

3
链接断开。特别是进入Apple文档。请考虑在此处从文档中提取关键元素。
levigroker

55

另一个较晚的答案,但该问题的现有答案都不能真正回答OP的问题,即:为什么要@objcprivate类成员上使用heck (如果@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使DistributedNotification使用Objective-C编写的代码才能通过其选择器调用的方法。

另一个@objc需要的常见情况是支持键值编码(KVC),尤其是在macOS上,其中KVC和KVO用于实现可可绑定。像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处理程序中手动发送通知。另外,通知dependentProperty依赖于KVC系统的静态属性originalProperty需要暴露给Objective-C,以便KVC系统找到并调用它,但它与我们代码的客户无关。

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

因此,正如您所看到的,有时可能需要将方法或属性公开给Objective-C以便与框架进行交互,而不必让代码的客户端可见。


25

@objc /动态

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

如果希望通过Objective-C代码或类访问属性/方法,请使用该方法。

在大多数情况下,当您将Objective-C基类的Swift类作为子类时,就会发生这种情况。

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

这是关于苹果的文档@objc

从Objective-C使用Swift

语言互操作性兼容性

链接已更新:
看起来这些链接已被Apple更新。


11

@objc是一个类属性,因此您可以使用

@objc public class MyClass

它将类的方法公开给Objective C类,因此只有在类包含公共函数的情况下才使用它


7

答案很晚,但是@objc从Swift 4(在Xcode 9中发布,该版本通常在10天前发布)开始,这种行为就有所变化。

在Swift 4中,@objc删除了的一些推断情况。这只是意味着在某些其他情况下,在@objcSwift编译器推断出标头之前,Swift 4中并未推断出标头。

在Swift提案中阅读有关此更改的更多信息

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


1
所以这应该是为什么在更新到Swift 4之后无法从ObjC访问某些变量的原因吗?使用Swift 3.X无需添加@objc
rgkobashi

哦,好的,与其他人仔细检查总是很好,谢谢!
rgkobashi

1

@objc向公开声明Objective-C runtime。让我们看一下#selector使用Objective-C运行时的Swift功能。在这种情况下,您可以定义您的Swift @objc private func[更多]

要从Objective-C使用Swift的功能:

  1. 斯威夫特的课应该从 NSObject
  2. 马克·斯威夫特(Mark Swift):

    一种。仅用于@objcMembers -公开所有 public 构造函数字段方法。也适用于子类

    b。@objc 类/枚举/协议struct除外)[命名类型]

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

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

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

例如:

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

[@objcdynamic]

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.