Когда использовать @objc в Swift?

87

В Swift я вижу такие методы, как:

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

Мне было интересно, когда использовать @objc? Я читал некоторые документы, но они говорят, что если вы хотите, чтобы его можно было вызывать в Objective-C, вы должны добавить флаг @objc

Однако это частная функция в Swift, что делает @obj?

Wingzero
источник
1
хороший вопрос !!!
Эрхан

Ответы:

67

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, и частный? Вы хотите сказать, что классы Objective-C могут перезаписывать doubleTapGestureRecognized?
Wingzero
1
Я думаю, потому что в obj-c вы все равно можете перезаписать любой метод.
Strangetimes 07
2
Не уверен, насколько этот ответ правильный, и отвечает на его вопрос. Ответы, представленные здесь, уже находятся в самом его вопросе, «но они говорят, что если вы хотите, чтобы его можно было вызывать в Objective-C, вы должны добавить флаг \ @objc», его основной Вопрос: «Это приватная функция в Swift, что делает \ @obj?»
KBJ
3
Ссылки рвутся. Особенно в документации Apple. Пожалуйста, подумайте об извлечении ключевых элементов из документации здесь.
levigroker
55

Еще один поздний ответ, но ни один из существующих ответов на этот вопрос на самом деле не отвечает на вопрос 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чтобы DistributedNotificationкод, написанный на Objective-C, мог вызывать его через свой селектор.

Другой распространенный случай, когда @objcэто необходимо, - это поддержка кодирования ключевого значения (KVC), особенно в macOS, где KVC и KVO используются для реализации привязок какао. 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 - в противном случае нам пришлось бы писать код для ручной отправки уведомлений в частное свойство willSetи didSetобработчики. Кроме того, статическое свойство, которое информирует систему KVC, которая dependentPropertyзависит от, originalPropertyнеобходимо предоставить Objective-C, чтобы система KVC находила и вызывала ее, но это не имеет отношения к клиентам нашего кода.

Кроме того, контроллер представления в приложении macOS, который обновляет элементы управления в своем представлении, используя привязки какао в качестве детали реализации, может сделать определенные частные свойства KVC-совместимыми, чтобы привязать к ним эти элементы управления.

Итак, как видите, бывают случаи, когда метод или свойство может потребоваться предоставить Objective-C, чтобы взаимодействовать с фреймворками, без необходимости быть видимыми для клиентов вашего кода.

Чарльз Срстка
источник
25

@objc / динамический

Это для совместимости: после импорта файла / кода Swift в проект на основе Objective-C.

И используйте это, если хотите, чтобы ваше свойство / метод были доступны для кода или класса Objective-C.

В большинстве случаев это происходит, когда вы подклассифицируете класс Swift базового класса Objective-C.

Класс или протокол Swift должны быть помечены атрибутом @objc, чтобы их можно было использовать в Objective-C. Этот атрибут сообщает компилятору, что к этой части кода Swift можно получить доступ из Objective-C. Если ваш класс Swift является потомком класса Objective-C, компилятор автоматически добавляет для вас атрибут @objc.

Вот документация Apple, в которой говорится о @objc.

Использование Swift из Objective-C

Совместимость языков

Ссылки обновлены:
похоже, что ссылки были обновлены компанией Apple.

0yeoj
источник
11

@objc - это атрибут класса, поэтому вы используете

@objc public class MyClass

Он предоставляет методы класса классам Objective C, поэтому вы будете использовать его только в том случае, если ваш класс содержит общедоступные функции.

Fraser
источник
7

Поздний ответ, но это @objcповедение немного изменилось, начиная с Swift 4 (который появился в Xcode 9, который обычно был выпущен 10 дней назад).

В Swift 4 некоторые случаи логического вывода @objcудалены. Это просто означает, что в некоторых дополнительных случаях, когда до того, как @objcзаголовок был выведен компилятором Swift, он не выводился в Swift 4.

Подробнее об этом изменении читайте в предложении Swift Evolution.

Как уже упоминалось, в целом @objcнеобходимо предоставить определенные методы среде выполнения Objective-C, которая является частью возможности взаимодействия языка Swift.

BHendricks
источник
1
так что это должно быть причиной того, что после обновления до Swift 4 некоторые переменные недоступны из ObjC, верно? В Swift 3.X необходимости добавлять не было@objc
rgkobashi
о, хорошо, всегда хорошо перепроверить с кем-нибудь, спасибо!
rgkobashi
1

@objc представляет декларацию Objective-C runtime . Давайте посмотрим на #selectorособенности Swift для использования среды выполнения Objective-C. В этом случае вы можете определить свой Swift @objc private func[Подробнее]

Чтобы использовать функции Swift из Objective-C:

  1. Класс Swift должен быть расширен с NSObject
  2. Марка Свифта:

    а. только @objcMembers класс - чтобы открыть все public конструкторы , поля и методы . Также это применимо для подклассов

    б. @objc класс / перечисление / протокол (кроме структуры ) [Именованный тип]

    • @objc class (необязательно) - выставить значение по умолчаниюpublic init() . Или@objc(<custom_name>) установить собственное имя для класса.
    • @objc конструкторы , поля и методы - чтобы выставлять их выборочно

Метод Swift будет доступен под следующим наименованием:

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

Например:

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

[ @objcи dynamic]

yoAlex5
источник