Использование Swift 3 @objc в режиме Swift 4 не рекомендуется?

485

Вкратце, при использовании Xcode 9 Beta я столкнулся со следующим предупреждением:

Использование Swift 3 @objc в режиме Swift 4 не рекомендуется. Обратите внимание на устаревшие предупреждения @objc, проверьте ваш код с включенным ведением журнала «Использование устаревшего Swift 3 @objc» и отключите Swift 3 @objc. **

После некоторых исследований я все еще не знаю, как решить проблему. Я был бы очень признателен за любые советы о том, как решить эту проблему, а также объяснение того, что происходит.

Моя цель - лучше понять, что происходит с моим кодом.

Далек
источник
4
Я действительно не получаю из предупреждающего сообщения, какой объект вызывает его. Xcode просто не говорит, в какой строке находится этот объект. Любые советы, как узнать, откуда это предупреждение?
olyv

Ответы:

816

Я избавился от этого предупреждения, изменив настройку сборки «Swift 3 @objc Inference» моих целей на «По умолчанию».

Отключить вывод Swift 3 @objc в Xcode9

Из этой статьи :

До Swift 4 компилятор делал некоторые объявления Swift автоматически доступными для Objective-C . Например, если один подкласс из NSObject, компилятор создал точки входа Objective C для всех методов в таких классах. Механизм называется выводом @objc.

В Swift 4 такой автоматический вывод @objc устарел, поскольку генерировать все эти точки входа в Objective-C дорого. Если для параметра «Swift 3 @objc Inference» установлено значение «Вкл.», Это позволяет старому коду работать. Тем не менее, он покажет предупреждения об устаревании, которые необходимо устранить. Рекомендуется «исправить» эти предупреждения и переключить настройку на «По умолчанию» , которая используется по умолчанию для новых проектов Swift.

Пожалуйста, также обратитесь к этому предложению Swift для получения дополнительной информации.

Евгений
источник
5
Спасибо Евгений. Это долгосрочное решение?
DaleK
6
@DaleK да, я верю в это. Согласно предложению Свифта, которое я упомянул в своем ответе, вывод объекта устарел. Параметр «Вывод объекта Swift 3» присутствует только в проектах, которые были перенесены из более старых версий Swift. Если создается новый проект, настройка больше не присутствует, что означает, что вывод объекта отключен. Рекомендуется обратиться к любым предупреждениям об объектном выводе и установить для него значение «Выкл.».
Евгений
4
Информационное сообщение в XCode говорит о том, что: «Использование @objcвывода Swift 3 в режиме Swift 4 не рекомендуется. Пожалуйста, устраните устаревшие @objcпредупреждения вывода, протестируйте свой код с @objcвключенным ведением журнала « Использование устаревшего вывода Swift 3 » и отключите вывод Swift 3 @objc». Есть идеи, где включить регистрацию Swift 3 @objc?
courteouselk
4
@courteouselk, согласно предложению Swift, можно установить для переменной среды SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT значения от 1 до 3, чтобы увидеть использование точек входа Objective C в журналах.
Евгений
14
Просто чтобы добавить - Вы должны сделать это для всех сборочных тагетов, а не только для проекта.
Криввенц
270

- Что такое @objcвывод? Что здесь происходит?

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

В Swift 4, компилятор больше не делает это (так много). Теперь вы должны добавить @objcявно.

По умолчанию, если у вас есть проект до Swift 4, вы получите предупреждения об этом. В проекте Swift 4 вы получите ошибки сборки. Это контролируется SWIFT_SWIFT3_OBJC_INFERENCEнастройкой сборки. В проекте до Swift 4 это установлено на On. Я бы порекомендовал установить это значение Default(или Off), которое теперь является параметром по умолчанию для нового проекта.

Конвертация всего займет некоторое время, но поскольку это Swift 4 по умолчанию, его стоит сделать.

Я могу остановить предупреждения / ошибки компилятора?

Существует два способа преобразования вашего кода, чтобы компилятор не жаловался.

Один из них - использовать @objcкаждую функцию или переменную, которые должны быть доступны среде выполнения Objective C:

@objc func foo() {

}

Другой заключается в использовании @objcMembersпо Classдекларации. Это гарантирует автоматическое добавление @objcко ВСЕМ функциям и переменным в классе. Это простой способ, но он имеет свою стоимость, например, он может увеличить размер вашего приложения, предоставляя функции, которые не нужно показывать.

@objcMembers class Test {

}

- Что @objcи зачем это нужно?

Если вы вводите новые методы или переменные в класс Swift, пометьте их как @objcвыставляющие их для среды выполнения Objective-C. Это необходимо, если у вас есть код Objective C, который использует ваш класс Swift, или если вы используете функции типа Objective C, например Selectors. Например, шаблон target-action: button.addTarget(self, action:#selector(didPressButton), for:.touchUpInside)

- Почему бы мне не отметить все @objc?

Есть негативы, которые помечаются как @objc:

  • Увеличенный размер двоичного файла приложения
  • Нет перегрузки функции

Пожалуйста, имейте в виду, что это резюме очень высокого уровня и что оно сложнее, чем я написал. Я бы порекомендовал прочитать актуальное предложение для получения дополнительной информации.

Источники:

kgaidis
источник
@objcне подразумевает динамическую диспетчеризацию, Swift может свободно использовать статическую или виртуальную диспетчеризацию (и, возможно, в результате выполнить другой код). dynamicКлючевым слово требуется , чтобы заставить Swift использовать динамическую диспетчеризацию.
Кевином
7
Есть ли другие способы добавить действие к кнопке? Если @objcуценено, что мы должны использовать?
Азникс
5
@ Стефан: да, там может быть немало для конвертации. Разделите это на этапы. Оставьте SWIFT_SWIFT3_OBJC_INFERENCEв On. Конвертировать в Swift 4. Затем заняться @objcвещами. Чтобы сделать это простым, следуйте основным правилам: ЕСЛИ класс Swift используется в коде Objc-C (через заголовок моста), используйте @objcMembers, в противном случае, одно за другим добавление @objc. Просто используйте поиск XCode, чтобы узнать, вызывается ли класс Swift из какого-либо .mфайла. Это должно сделать преобразование относительно безболезненным.
kgaidis
5
@DaleK это должен быть принят ответ. Подавлять предупреждения и заставлять вещи работать так, как они были в Swift 3, - вариант, но ИМХО не самый лучший. Важно понять, почему @objcв Swift 4 произошли изменения, а затем принять решение исправить проект и оставить его прежним.
Дерполюк
2
Спасибо за это краткое объяснение
Schmoudi
48

Migrator не может идентифицировать все функции, для которых нужны блоки @objc Inferred Objective-C, помеченные как устаревшие, чтобы помочь вам их найти.
• Создавать предупреждения о устаревших методах.
• Консольные сообщения при запуске устаревших блоков.

введите описание изображения здесь

Хасан Талеб
источник
1
Так что мне делать с @objc? убери это? Оставь это? Я уже удалил это. и я получил эти предупреждения, поэтому я должен добавить их? что на шаге 3 мне делать с этим?
Шиал
Добавьте @objc как раз перед func
Хасан Талеб
1
о каком шаге 3 идет речь? Вы можете добавить некоторые описания :)
Shial
И в моем случае я получаю это предупреждение, но на код не указывается. Есть два метода, помеченных @objc, и они кажутся единственными, которым это нужно. Я изменил его на Default и по-прежнему получаю предупреждения во время компиляции.
Мори Марковиц
12

У меня было это предупреждение с настройкой «Swift 3 @objc Inference» = «По умолчанию». Тогда я понял, что это было установлено для Проекта, а не для цели. Итак, убедитесь, что у вас есть настройка «Default» в вашей цели, чтобы избавиться от предупреждения.

Дмитрий
источник
Я потратил впустую 20 минут, пытаясь устранить ошибку, даже после того, как я изменил значение по умолчанию в настройках проекта Вы указали точно, что это должно быть изменено в цели также.
SkrewEverything
8

Вы можете просто перейти на «по умолчанию» вместо «ON». Кажется, более привержен к логике Apple.

(но все остальные комментарии об использовании @objостаются в силе.)

ingconti
источник
7

Действительно, вы избавитесь от этих предупреждений, отключив Swift 3 @objc Inference. Тем не менее, могут возникнуть тонкие проблемы. Например, КВО перестанет работать. Этот код отлично работал под Swift 3:

for (key, value) in jsonDict {
    if self.value(forKey: key) != nil {
        self.setValue(value, forKey: key)
    }
}

После перехода на Swift 4 и установки по умолчанию «Swift 3 @objc Inference» некоторые функции моего проекта перестали работать . Мне потребовались некоторые отладки и исследования, чтобы найти решение для этого. Насколько я знаю, вот варианты:

  • Включить «Swift 3 @objc Inference» (работает, только если вы перенесли существующий проект из Swift 3) введите описание изображения здесь
  • Отметьте затронутые методы и свойства как @objc введите описание изображения здесь
  • Снова включите вывод ObjC для всего класса, используя @objcMembers. введите описание изображения здесь

Повторное включение вывода @objc оставляет вас с предупреждениями, но это самое быстрое решение. Обратите внимание, что он доступен только для проектов, перенесенных из более ранней версии Swift. Два других варианта более утомительны и требуют некоторого копания кода и тщательного тестирования.

Смотрите также https://github.com/apple/swift-evolution/blob/master/proposals/0160-objc-inference.md

Кароли Нийзор
источник
7

Я случайный разработчик iOS (скоро будет больше), но я все еще не мог найти настройку, руководствуясь другим ответом (так как у меня не было этого элемента Keychain, который показывает ответ), так что теперь, когда я нашел его, я подумал Я мог бы просто добавить этот снимок с выделенными местами, которые вам нужно будет щелкнуть и найти.

  1. Начало в верхнем левом углу
  2. Выберите значок папки проекта
  3. Выберите название своего основного проекта под значком папки проекта.
  4. Выберите Настройки сборки на правой стороне.
  5. Выберите свой проект под ЦЕЛЕЙ.
  6. Прокрутка очень далеко вниз (или поиск слова в текстовом поле поиска)

Нахождение настройки

raddevus
источник
6

Вы можете попробовать "Pod update" и / или "flutter clean"

Я также установил эту настройку в xcode.

Настройка интерфейса Objective-C выглядит следующим образом:

Настройка интерфейса ObjectiveC

wisekiddo
источник
2

Swift 3 @objc Inference Использование Swift 3 @objc Inference в режиме Swift 4 не рекомендуется. Обратите внимание на устаревшие предупреждения @objc, проверьте ваш код с включенным ведением журнала «Использование устаревшего Swift 3 @objc», а затем отключите вывод, изменив настройку сборки «Swift 3 @objc Inference» на «По умолчанию» для «XMLParsingURL». цель.

добрался до

  1. Первый шаг получил настройки сборки

  2. Выполните поиск, чтобы построить вывод настроек

  3. change swift 3 @objc Inference Default

введите описание изображения здесь

Правин Кумар
источник
1

Все, что вам нужно, это просто запустить тестовое ожидание до конца, после этого перейдите в «Настройка сборки», «Поиск в выводе параметров сборки», измените swift 3 @objc Inference на (по умолчанию). это все, что я делал и работал отлично.

Acasey
источник
0

Использование Swift 3 @objc в режиме Swift 4 не рекомендуется?

используйте func call @objc

func call(){

foo()

}

@objc func foo() {

}
Пуджи Вахоно
источник
0

В дополнение к тому, что сказал @wisekiddo, вы также можете изменить настройки сборки в project.pbxprojфайле, установив для параметра Swift 3 @obj Inference значение по умолчанию, как SWIFT_SWIFT3_OBJC_INFERENCE = Default;для ваших вариантов сборки (т. Е. Отладка и выпуск), особенно если вы пришли из какой-то другой среды кроме Xcode

DaveNOTDavid
источник