Importer un protocole Swift en classe Objective-C

116

J'essaie d'importer un protocole Swift nommé AnalyticProtocoldans une classe Objective-C nommée AnalyticFactory.

protocol AnalyticProtocol
{

}

Je pars d'un projet Objective-C existant (je n'ai pas créé de nouveau projet Swift avec xCode et je n'ai pas trouvé comment configurer mon projet Objective-C pour être un projet Swift dans xCode 6 ).

Dans mon fichier Swift, j'ai inclus le .hfichier nommé MyProjectName-Swift.hmais le compilateur m'a renvoyé une erreur m'indiquant qu'il n'existe pas . Donc, j'ai créé un .hfichier nommé MyProjectName-Swift.hqui est en fait vide (je ne sais pas ce que je dois mettre à l'intérieur).

Dans la documentation Apple, ils ont dit que je devais inclure mon .hfichier nommé MyProjectName-Swift.hdans mon .mfichier. Mais je dois l'inclure non pas dans mon .mfichier mais dans mon fichier .h. Cela peut-il être problématique?

Lorsque j'essaie de compiler, j'ai cette erreur:: 0: erreur: xxxAnalyticFactory.h: 39: impossible de trouver la déclaration de protocole pour 'AnalyticProtocol'

Et le code incriminé:

@interface AnalyticFactory : NSObject
{
    Class<AnalyticProtocol> _analyticProtocolClass; // The type of the analytic class currently used.
}

Je pense que je ne comprends pas bien comment importer un protocole Swift dans une classe Objective-C.

Quelqu'un voit-il une erreur dans ce que je fais?

Jean Lebrument
la source
Regardez la vidéo Intégration de Swift avec Objective-C de la WWDC 2014. Vers 30 h 40 dans la vidéo, ils décrivent comment accéder aux protocoles Swift dans les classes Objective-C.
Jamie Forrest

Réponses:

224

Vous devez ajouter l' @objcattribut à votre protocole Swift comme suit:

@objc protocol AnalyticProtocol {

}
Jamie Forrest
la source
25
Merci pour votre réponse mais le problème persiste.
Jean Lebrument
Pourriez-vous publier un exemple de projet qui reproduit le problème?
Jamie Forrest
L'ajout de @objc m'a aidé à importer des classes Swift dans Obj-C
serg
19
@objc ne fonctionne pas toujours. Lorsque vous vous conformez à un protocole, cela ne fonctionne pas toujours lors de l'ajout du protocole @interfacedans le .hfichier. cependant, vous pouvez ajouter le protocole au privé @interfacedans le .mfichier et il corrige les choses (du moins il l'a pour moi à l'occasion). Donc au-dessus de votre @implementationavoir @interface MyController() <AnalyticProtocol>.
Adam
1
Parfois, Xcode 8 se plaindra pendant que vous éditez, mais lorsque vous le construisez, en suivant cette réponse avec les commentaires, l'erreur disparaîtra.
Roger Pingleton
77

Il n'est pas possible d'importer l'en-tête Swift généré par Xcode dans les fichiers d'en-tête objC.

Donc, puisque vous souhaitez utiliser du code Swift dans un fichier d'en-tête objC, vous devrez "déclarer en avant" les classes et protocoles que vous souhaitez utiliser dans le fichier d'en-tête objC, comme ceci:

@protocol AnalyticProtocol;

Vous pouvez maintenant utiliser le protocole dans votre déclaration de classe objC:

@interface AnalyticFactory : NSObject
{
    Class<AnalyticProtocol> _analyticProtocolClass; // The type of the analytic class currently used.
}

Dans votre fichier d'implémentation (le fichier objC .m), vous pouvez importer le fichier d'en-tête Swift généré par Xcode ("ProductModuleName-Swift.h") et l'implémentation correcte AnalyticProtocolsera désormais connue du compilateur.

Ceci est également décrit dans la section «Utilisation de Swift à partir d'Objective-C» dans la documentation Apple

Notez que XCode donnera un avertissement dans le fichier d'en-tête objC lorsque vous utilisez le protocole déclaré avant ("Impossible de trouver la définition de protocole pour 'AnalyticProtocol'), mais cela peut être ignoré - l'implémentation sera trouvée au moment de la compilation.

Pelle Stenild Coltau
la source
19
Pourquoi Xcode affiche-t-il l'avertissement de protocole manquant lorsqu'il se compile et fonctionne correctement? Un moyen de supprimer l'avertissement?
Oren
Cependant, il n'est toujours pas possible d'appeler les méthodes de protocole sur cette classe. Il donnera l'erreurNo visible @interface for <ClassName> declares the selector <protocolMethodName>
Elsa
il produit l'avertissement suivant: "Impossible de trouver la définition de protocole pour xxxx"
JAHelia
51

Pour quiconque a simplement besoin d'adopter un protocole - vous pouvez le faire en deux étapes, sans générer d'avertissements ou d'erreurs:

  1. Dans votre .swiftfichier, ajoutez @objcavant le nom du protocole:

    @objc protocol AnalyticProtocol {
    
    }
  2. Dans votre .mfichier, importez l'en-tête Swift généré et adoptez le protocole dans une catégorie privée. (Le fichier d'en-tête est nommé automatiquement):

    #import "ProductModuleName-Swift.h"
    
    @interface AnalyticFactory () <AnalyticProtocol>
    
    @end

C'est l'approche recommandée par Apple. Vous pouvez en savoir plus sur le mélange et la correspondance entre Objective-C et Swift ici: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

Chris Nolet
la source
1
Je reçois toujours un avertissement, avec ou sans déclaration préalable. J'utilise le protocole dans une extension.
Cristi Băluță
Impossible d'importer #import "AnalyticProtocol-Swift.h". On dirait que WhateverProtocol-Swift.h n'est pas généré automatiquement comme vous l'avez dit.
Hlung
2
Cela a fonctionné pour moi; aucune autre suggestion ou réponse sur cette page n'a fonctionné. Je suis sur Swift 4.
Poulsbo
1
C'était le seul moyen de supprimer l'avertissement (même si cela fonctionne lorsque les protocoles sont dans le fichier d'en-tête)
David P
1
Le même lien est disponible via WebArchive: web.archive.org/web/20170310053717/https
Richard Topchii
3

Si vous créez un framework, l'importation requise

#import "ProductModuleName-Swift.h"

change pour:

#import <ProductModuleName/ProductModuleName-Swift.h>

Dans ce cas, vous devez également rendre public le protocole swift :

@objc public protocol AnalyticProtocol {
  func something();
}
Michal
la source
3

Nous pouvons utiliser des protocoles rapides en Objective C avec quelques modifications du code. De plus, les protocoles déclarés @objc vous permettent d'avoir des méthodes facultatives et obligatoires sans implémentations par défaut. Il comporte des avantages et des inconvénients.

Nous pourrions en fait renommer le nom du protocole en un nom plus descriptif lors de l'utilisation en Objective C. J'utilise "@objc (alias_name)".

Voici le code, ayons un protocole rapide avec l'attribut @objc et le nom d'alias à utiliser dans le code ObjC.

@objc(ObjTableViewReloadable) protocol TableViewReloadable: class {
   func reloadRow(at index: IndexPath)
   func reloadSection(at index: Int)
   func reloadTable()
}

Laissons maintenant farword déclarer notre protocole dans un fichier .h

@protocol ObjTableViewReloadable;

Vous pouvez maintenant vous conformer à ce protocole dans le fichier .m et ajouter l'implémentation des méthodes requises.

#import "MyApp-Swift.h"
@interface MyObjcViewController () <ObjTableViewReloadable>
Vinay Hosamane
la source
Merci d'avoir posté ceci. Je regarde du code hérité qui est plus ancien que la saleté et si cette approche fonctionne, cela me sauvera beaucoup de douleur. :)
Adrian le