web-dev-qa-db-fra.com

Comment éviter les références circulaires lorsque l'en-tête de pontage Swift importe un fichier qui importe Hopscotch-Swift.h lui-même

J'intègre Swift dans un grand projet Objective C existant et je me suis heurté à ce que je pense être une référence circulaire. 

Les classes en question sont les suivantes: 

Contrôleur Objective C

#import "Hopscotch-Swift.h"

@interface MyController : UIViewController<MyProtocol>
   ...
@end

Protocole rapide

@objc protocol MyProtocol: NSObjectProtocol {
   ...
}

En-tête de pontage

#import "MyController.h"

La compilation de ce code échoue car le fichier Hopscotch-Swift.h ne sera pas généré. 

Je pense que cela est dû à une erreur de référence circulaire car je peux importer Hopscotch-Swift.h dans des en-têtes Objective C qui ne sont pas inclus dans Hopscotch-Bridging-Header.h et cela fonctionne correctement.

Existe-t-il une solution de contournement à ce problème ou devrais-je enregistrer un radar auprès d'Apple? 

36
Samantha John

La déclaration à terme devrait fonctionner dans votre cas.

Dans votre .h:

@protocol MyProtocol;

@interface MyController : UIViewController<MyProtocol>

@end

Dans votre .m:

#import "HopScotch-Swift.h"

De Comment puis-je ajouter des références de classe avant utilisées dans l'en-tête -Swift.h? et le guide d'interopérabilité Swift:

Si vous utilisez vos propres types Objective-C dans votre code Swift, veillez à importer les en-têtes Objective-C de ces types avant d'importer l'en-tête généré par Swift dans le fichier .mob Objective-C à partir duquel vous souhaitez accéder au code Swift.

24
rudd

Je me suis heurté à cela en essayant d'utiliser des classes Swift dans les protocoles Objective-C, où le protocole était également implémenté par une autre classe Swift. Cela empestait les références circulaires et j’imaginais que ce pourrait être un problème d’essayer de générer de manière circulaire les en-têtes de pontage, plutôt qu’un problème d’inclusion «normal». 

La solution, pour moi, consistait simplement à utiliser les déclarations anticipées avant la déclaration de protocole: -

// don't include the MyProject-Swift.h header

// forward declaration of Swift classes used
@class SwiftClass;

@protocol MyProtocol <NSObject>
- (SwiftClass *)swiftClass;
@end
9
Echelon

La déclaration anticipée par elle-même ne m'a pas fonctionné. Il a compilé sans erreurs mais il y avait toujours des avertissements que le protocole était introuvable. Je traite tous les avertissements comme des erreurs, donc cela ne suffit pas.

J'ai pu résoudre ce problème en déplaçant la mise en œuvre du protocole dans un autre en-tête de catégorie.

Alors voici ce qui a fonctionné pour moi:

Dans mon MyOtherSwiftFile.Swift:

@objc protocol MyProtocol: class {
func viewController(didFinishEditing viewController: MyViewController)
}

Dans mon MyViewController.h:

@interface MyViewController // Removed protocol implementation declaration here
@end

Ajout de MyViewController + MyProtocol.h pour projeter et mettre ceci dans:

@interface MyViewController (MyProtocol) <MyProtocol>
@end

Les méthodes elles-mêmes peuvent rester où elles sont si vous voulez.

Une fois que vous avez implémenté ce qui précède et que vous avez compilé, vous obtenez des avertissements du compilateur quelque part dans votre code qui nécessite que MyViewController implémente MyProtocol. Dans ce fichier, vous allez #import "MyViewController+MyProtocol.h"

0
Chris Garrett