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


87

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

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

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

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


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.


11

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

@objc public class MyClass

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


7

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

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

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

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


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]

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.