L'utilisation de l'inférence Swift 3 @objc en mode Swift 4 est-elle déconseillée?

485

En bref, lors de l'utilisation de Xcode 9 Beta, j'ai rencontré l'avertissement suivant:

L'utilisation de l'inférence Swift 3 @objc en mode Swift 4 est déconseillée. Veuillez adresser les avertissements d'inférence @objc obsolètes, testez votre code avec la journalisation «Utilisation de l'inférence Swift 3 @objc obsolète» activée et désactivez l'inférence Swift 3 @objc. **

Après quelques recherches, je n'ai toujours aucune idée de comment résoudre le problème. J'apprécierais grandement tous les conseils sur la façon de résoudre ce problème ainsi qu'une explication de ce qui se passe.

Mon objectif est de mieux comprendre ce qui se passe avec mon code.

DaleK
la source
4
Je ne reçois pas vraiment du message d'avertissement quel objet est à l'origine de cela. Xcode ne dit simplement pas dans quelle ligne se trouve cet objet. Des conseils pour savoir d'où vient cet avertissement?
olyv

Réponses:

816

Je me suis débarrassé de cet avertissement en changeant le paramètre de construction "Swift 3 @objc Inference" de mes cibles sur "Par défaut".

Désactiver l'inférence Swift 3 @objc dans Xcode9

De cet article :

Avant Swift 4, le compilateur mettait automatiquement certaines déclarations Swift à la disposition d'Objective-C . Par exemple, si une sous-classe de NSObject, le compilateur a créé des points d'entrée Objective-C pour toutes les méthodes de ces classes. Le mécanisme s'appelle l'inférence @objc.

Dans Swift 4, une telle inférence @objc automatique est obsolète car il est coûteux de générer tous ces points d'entrée Objective-C. Lorsque le paramètre "Swift 3 @objc Inference" est défini sur "On", il permet à l'ancien code de fonctionner. Cependant, il affichera des avertissements de dépréciation qui doivent être traités. Il est recommandé de «corriger» ces avertissements et de basculer le paramètre sur «Default» , qui est la valeur par défaut pour les nouveaux projets Swift.

Veuillez également vous référer à cette proposition Swift pour plus d'informations.

Evgenii
la source
5
Merci Evgenii. Est-ce une solution à long terme?
DaleK
6
@DaleK oui, je le crois. Selon la proposition Swift que j'ai mentionnée dans ma réponse, l'inférence objc est déconseillée. Le paramètre "Swift 3 objc Inference" est uniquement présent dans les projets qui ont été migrés à partir d'anciennes versions de Swift. Si l'on crée un nouveau projet, le paramètre n'est plus présent, ce qui signifie que l'inférence objc est désactivée. Il est recommandé de traiter tous les avertissements d'inférence objc et de le régler sur "Off".
Evgenii
4
Le message d'information dans XCode suggère que: "L'utilisation de l' @objcinférence Swift 3 en mode Swift 4 est obsolète. Veuillez adresser @objcles avertissements d'inférence obsolètes , tester votre code avec la @objcjournalisation " Utilisation de l' inférence Swift 3 obsolète "activée et désactiver l' @objcinférence Swift 3. " Une idée où activer la @objcjournalisation de l'inférence Swift 3 ?
courtouselk
4
@courteouselk, selon la proposition Swift, on peut définir la variable d'environnement SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT sur des valeurs de 1 à 3 pour voir les utilisations des points d'entrée Objective-C dans les journaux.
Evgenii
14
Juste pour ajouter - Vous devez le faire pour tous les tagets de build, pas seulement pour le projet.
Krivvenz
270

- Qu'est-ce que l' @objcinférence? Que se passe-t-il?

Dans Swift 3, le compilateur déduit @objcà un certain nombre d'endroits pour que vous n'ayez pas à le faire. En d'autres termes, il s'assure d'ajouter @objcpour vous!

Dans Swift 4, le compilateur ne fait plus cela (autant). Vous devez maintenant ajouter @objcexplicitement.

Par défaut, si vous avez un projet pré-Swift 4, vous recevrez des avertissements à ce sujet. Dans un projet Swift 4, vous obtiendrez des erreurs de génération. Ceci est contrôlé via le SWIFT_SWIFT3_OBJC_INFERENCEparamètre de construction. Dans un projet antérieur à Swift 4, ce paramètre est défini sur On. Je recommanderais de régler ce paramètre surDefault (ou Off), qui est maintenant l'option par défaut sur un nouveau projet.

Il faudra un certain temps pour tout convertir, mais comme c'est la valeur par défaut pour Swift 4, cela vaut la peine.

- Comment puis-je arrêter les avertissements / erreurs du compilateur?

Il existe deux façons de convertir votre code afin que le compilateur ne se plaint pas.

L'une consiste à utiliser @objcsur chaque fonction ou variable qui doit être exposée au runtime Objective-C:

@objc func foo() {

}

L'autre est d'utiliser @objcMemberspar une Classdéclaration. Cela garantit d'ajouter automatiquement @objcà TOUTES les fonctions et variables de la classe. C'est le moyen le plus simple, mais cela a un coût, par exemple, il peut augmenter la taille de votre application en exposant des fonctions qui n'ont pas besoin d'être exposées.

@objcMembers class Test {

}

- Qu'est-ce que c'est @objcet pourquoi est-il nécessaire?

Si vous introduisez de nouvelles méthodes ou variables dans une classe Swift, les marquer comme les @objcexpose au runtime Objective-C. Cela est nécessaire lorsque vous avez du code Objective-C qui utilise votre classe Swift ou, si vous utilisez des fonctionnalités de type Objective-C comme Selectors. Par exemple, le modèle d'action cible: button.addTarget(self, action:#selector(didPressButton), for:.touchUpInside)

- Pourquoi ne marquerais-je pas tout @objc?

Il y a des négatifs qui accompagnent le marquage de quelque chose comme @objc:

  • Augmentation de la taille binaire de l'application
  • Pas de surcharge de fonction

Veuillez garder à l'esprit qu'il s'agit d'un résumé de très haut niveau et qu'il est plus compliqué que je ne l'ai écrit. Je recommanderais de lire la proposition actuelle pour plus d'informations.

Sources:

kgaidis
la source
@objcn'implique pas de répartition dynamique, Swift est libre d'utiliser la répartition statique ou virtuelle (et éventuellement d'exécuter du code différent en conséquence). Le dynamicmot clé est requis pour forcer Swift à utiliser la répartition dynamique.
Kevin
7
Existe-t-il d'autres façons d'ajouter une action au bouton? Si @objcprivé, que devons-nous utiliser?
Aznix
5
@Stefan oui, il y a peut-être beaucoup à convertir. Divisez-le en étapes. Partez SWIFT_SWIFT3_OBJC_INFERENCEà On. Convertissez en Swift 4. Ensuite, attaquez le @objctruc. Pour faire simple, suivez les règles de base: SI la classe Swift est utilisée dans le code Objc-C (via un en-tête de pontage), utilisez @objcMembers, sinon, un par un @objc. Utilisez simplement la recherche Xcode pour savoir si la classe Swift est appelée à partir de n'importe quel .mfichier. Cela devrait rendre la conversion relativement indolore.
kgaidis
5
@DaleK, cette réponse doit être acceptée. Supprimer les avertissements et faire fonctionner les choses comme elles l'étaient dans Swift 3 est une option, mais à mon humble avis pas la meilleure. Il est important de comprendre pourquoi a @objcchangé dans Swift 4, puis de prendre la décision de corriger le projet et de le conserver.
derpoliuk
2
Merci pour cette courte explication
Schmoudi
48

Migrator ne peut pas identifier toutes les fonctions qui ont besoin @objc inférées Objective-C Thunks marqué comme dépréciée pour vous aider à les trouver
• Construire des avertissements sur les méthodes dépréciées
de messages console lorsque thunks en cours d' exécution dépréciée

entrez la description de l'image ici

Hassan Taleb
la source
1
Alors, que dois-je faire avec @objc? l'enlever? laisse le? J'ai déjà supprimé cela. et je dois ces avertissements donc je dois les ajouter? qu'à l'étape 3 devrais-je faire avec ça?
Shial
Ajouter @objc juste avant func
Hassan Taleb
1
de quelle étape 3 s'agit-il? Vous pouvez ajouter quelques descriptions :)
Shial
Et dans mon cas, je reçois cet avertissement, mais aucun code n'est pointé. Il existe deux méthodes marquées @objc et elles semblent être les seules à en avoir besoin. Je l'ai changé par défaut et j'obtiens toujours les avertissements pendant la compilation.
Maury Markowitz
12

J'ai eu cet avertissement avec le paramètre "Swift 3 @objc Inference" = "Default". Puis j'ai réalisé que c'était réglé pour le projet - pas pour la cible. Assurez-vous donc que vous disposez du paramètre "Par défaut" dans votre cible pour vous débarrasser de l'avertissement.

Dmitry
la source
J'ai perdu 20 minutes à chercher à résoudre l'erreur même après avoir changé pour Default dans les paramètres du projet. Vous avez également souligné le besoin de changer d'objectif également.
SkrewEverything
8

Vous pouvez simplement passer à "par défaut" au lieu de "ON". Semble plus adhérent à la logique d'Apple.

(mais tous les autres commentaires sur l'utilisation de @objrestent valables.)

ingconti
la source
7

En effet, vous vous débarrasserez de ces avertissements en désactivant Swift 3 @objc Inference. Cependant, des problèmes subtils peuvent apparaître. Par exemple, KVO cessera de fonctionner. Ce code fonctionnait parfaitement sous Swift 3:

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

Après la migration vers Swift 4 et la définition par défaut de «Swift 3 @objc Inference», certaines fonctionnalités de mon projet ont cessé de fonctionner . Il m'a fallu un débogage et des recherches pour trouver une solution. Selon ma meilleure connaissance, voici les options:

  • Activer "Swift 3 @objc Inference" (ne fonctionne que si vous avez migré un projet existant à partir de Swift 3) entrez la description de l'image ici
  • Marquer les méthodes et propriétés affectées comme @objc entrez la description de l'image ici
  • Réactivez l'inférence ObjC pour toute la classe à l'aide de @objcMembers entrez la description de l'image ici

Réactiver l'inférence @objc vous laisse avec les avertissements, mais c'est la solution la plus rapide. Notez qu'il n'est disponible que pour les projets migrés à partir d'une version antérieure de Swift. Les deux autres options sont plus fastidieuses et nécessitent des fouilles de code et des tests approfondis.

Voir également https://github.com/apple/swift-evolution/blob/master/proposals/0160-objc-inference.md

Karoly Nyisztor
la source
7

Je suis un développeur iOS occasionnel (bientôt plus) mais je ne pouvais toujours pas trouver le paramètre comme guidé par l'autre réponse (puisque je n'avais pas cet élément de trousseau que la réponse montre), alors maintenant que je l'ai trouvé, je pensais Je pourrais simplement ajouter cet instantané avec les emplacements en surbrillance que vous devrez cliquer et trouver.

  1. Commencez en haut à gauche
  2. Choisissez l'icône du dossier du projet
  3. Choisissez le nom de votre projet principal sous l'icône du dossier de projet.
  4. Choisissez Build Settings sur le côté droit.
  5. Choisissez votre projet sous CIBLES.
  6. Faites défiler très loin (ou recherchez l'inférence de mot dans la zone de texte de recherche)

Recherche du paramètre

raddevus
la source
6

Vous pouvez essayer de «mettre à jour le pod» et / ou de «flutter clean»

J'ai également défini ce paramètre dans xcode.

Le paramètre d'interface Objective-C est le suivant:

Paramètre d'interface ObjectiveC

sage
la source
2

Inférence Swift 3 @objc L'utilisation de l'inférence Swift 3 @objc en mode Swift 4 est déconseillée. Veuillez adresser les avertissements d'inférence @objc obsolètes, testez votre code avec la journalisation «Utilisation de l'inférence Swift 3 @objc obsolète» activée, puis désactivez l'inférence en modifiant le paramètre de génération «Swift 3 @objc Inference» sur «Par défaut» pour «XMLParsingURL» cible.

arrivé au

  1. La première étape a obtenu le paramètre de construction

  2. Rechercher pour construire l'inférence de paramètre

  3. changer swift 3 @objc Inference Default

entrez la description de l'image ici

Praveen Kumar
la source
1

Tout ce dont vous avez besoin est d'exécuter un test, attendez la fin, après cela allez dans Build Setting, recherchez dans Build Setting Inference, changez swift 3 @objc Inference en (Default). c'est tout ce que j'ai fait et travaillé parfaitement.

Acasey
la source
0

L'utilisation de l'inférence Swift 3 @objc en mode Swift 4 est-elle déconseillée?

utilisez func call @objc

func call(){

foo()

}

@objc func foo() {

}
Puji Wahono
la source
0

En plus de ce que @wisekiddo a dit, vous pouvez également modifier vos paramètres de build dans le project.pbxprojfichier en définissant l'inférence Swift 3 @obj par défaut comme SWIFT_SWIFT3_OBJC_INFERENCE = Default;pour vos versions de build (c.-à-d. Déboguer et publier), surtout si vous venez d'un autre environnement en plus de Xcode

DaveNOTDavid
la source