Я пытаюсь преобразовать исходный код своего проекта из Swift 3 в Swift 4. Одно предупреждение, которое дает мне Xcode, касается моих селекторов.
Например, я добавляю цель к кнопке, используя обычный селектор вроде этого:
button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)
Это предупреждение, которое он показывает:
Аргумент '#selector' относится к методу экземпляра 'myAction ()' в 'ViewController', который зависит от вывода атрибута '@objc', устаревшего в Swift 4
Добавьте '@objc', чтобы предоставить этот метод экземпляра Objective-C
Теперь нажатие Fix
на сообщение об ошибке делает это с моей функцией:
// before
func myAction() { /* ... */ }
// after
@objc func myAction() { /* ... */ }
Я действительно не хочу переименовывать все свои функции, чтобы включить @objc
метку, и предполагаю, что в этом нет необходимости.
Как мне переписать селектор, чтобы справиться с устареванием?
Связанный вопрос:
@objc
это теперь необходимо для того , чтобы подвергнуть их Obj-C, и , следовательно , использовать с селекторов.@objc
? Это немного раздражает, но я обычно делаю эти функции закрытыми, требуя от меня пометить их как в@objc
любом случае.@objcMembers
для того, чтобы предоставить Obj-C все совместимые с Obj-C члены, но я бы не советовал этого делать, если вам действительно не нужно, чтобы весь ваш класс был открыт.Ответы:
Исправление - это правильно - в селекторе нет ничего, что вы могли бы изменить, чтобы сделать метод, к которому он относится, доступным для Objective-C.
Вся причина этого предупреждения в первую очередь - результат SE-0160 . До Swift 4
internal
или выше Objective-C совместимые членыNSObject
наследующих классов предполагались@objc
и, следовательно, были доступны для Objective-C, что позволяло их вызывать с помощью селекторов (поскольку для поиска метода требуется среда выполнения Obj-C реализация для данного селектора).Однако в Swift 4 это уже не так. Теперь предполагается, что только очень конкретные объявления могут быть
@objc
, например, переопределениями@objc
методов, реализациями@objc
требований протокола и объявлениями с атрибутами, которые подразумевают@objc
, например@IBOutlet
.Мотивация, стоящая за этим, как подробно описано в приведенном выше связанном предложении , состоит во-первых, чтобы предотвратить конфликты перегрузок методов в
NSObject
наследующих классах друг с другом из-за наличия идентичных селекторов. Во-вторых, это помогает уменьшить размер двоичного файла, не создавая преобразователей для членов, которые не должны быть открыты для Obj-C, и, в-третьих, повышает скорость динамического связывания.Если вы хотите предоставить доступ к члену Obj-C, вам нужно пометить его
@objc
, например, как:(мигратор должен делать это автоматически с помощью селекторов при работе с выбранной опцией «минимизировать вывод»)
Чтобы предоставить группу участников Obj-C, вы можете использовать
@objc extension
:Это откроет все элементы, определенные в нем, для Obj-C и выдаст ошибку для любых членов, которые не могут быть представлены Obj-C (если явно не отмечены как
@nonobjc
).Если у вас есть класс, в котором все совместимые с Obj-C члены должны быть доступны для Obj-C, вы можете пометить класс как
@objcMembers
:Теперь все члены, которых можно предположить,
@objc
будут. Однако я бы не советовал делать это, если вам действительно не нужны все члены, открытые для Obj-C, с учетом вышеупомянутых недостатков необоснованного раскрытия членов.источник
@IBAction
тоже автоматически@objc
? До сих пор этого не было, но это было бы логично. EDIT: nvm, в предложении четко указано, что этого@IBAction
достаточно для существования метода@objc
.Как официальная документация Apple . вам нужно использовать @objc для вызова вашего метода выбора.
источник
Насколько я понимаю, Swift 4.2, все, что вам нужно сделать, это назначить @IBAction вашему методу, и вы можете избежать этой глупой аннотации @objc
`` `
источник
Как уже упоминалось в других ответах, нет возможности избежать
@objc
аннотации для селекторов.Но предупреждение, упомянутое в OP, можно отключить, выполнив следующие действия:
Off
ниже приведен снимок экрана, который иллюстрирует вышеупомянутые шаги:
Надеюсь это поможет
источник
Если вам нужны члены объекта c в вашем контроллере представления, просто добавьте @objcMembers в верхней части контроллера представления. А этого можно избежать, добавив в код IBAction.
Обязательно подключите эту розетку в раскадровке.
источник