Importazione di un protocollo Swift nella classe Objective-C


116

Provo a importare un protocollo Swift denominato AnalyticProtocolin una classe Objective-C denominata AnalyticFactory.

protocol AnalyticProtocol
{

}

Sto iniziando da un progetto Objective-C esistente (non ho creato un nuovo progetto Swift con xCode e non ho trovato come configurare il mio progetto Objective-C per essere un progetto Swift in xCode 6 ).

Nel mio file Swift ho incluso il .hfile denominato MyProjectName-Swift.hma il compilatore mi ha restituito un errore dicendomi che non esiste . Quindi, ho creato un .hfile denominato MyProjectName-Swift.hche in realtà è vuoto (non so cosa dovrei mettere dentro).

Nella documentazione Apple hanno detto che devo includere il mio .hfile denominato MyProjectName-Swift.hnel mio .mfile. Ma ho bisogno di includerlo non nel mio .mfile ma nel mio .h. Questo può essere problematico?

Quando provo a compilare ho questo errore:: 0: errore: xxxAnalyticFactory.h: 39: impossibile trovare la dichiarazione di protocollo per 'AnalyticProtocol'

E il codice incriminato:

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

Penso di non capire bene come posso importare un protocollo Swift in una classe Objective-C.

Qualcuno vede un errore in quello che sto facendo?


Guarda il video Integrating Swift With Objective-C del WWDC 2014. Intorno alle 30:40 del video, descrivono come accedere ai protocolli Swift nelle classi Objective-C.
Jamie Forrest

Risposte:


224

Devi aggiungere l' @objcattributo al tuo protocollo Swift in questo modo:

@objc protocol AnalyticProtocol {

}

25
Grazie per la tua risposta, ma il problema persiste.
Jean Lebrument

Potresti forse pubblicare un progetto di esempio che riproduca il problema?
Jamie Forrest

L'aggiunta di @objc mi ha aiutato a importare le classi Swift in Obj-C
serg

19
@objc non funziona sempre. Quando ci si conforma a un protocollo a volte non funziona quando si aggiunge il protocollo @interfacenel .hfile. tuttavia, puoi aggiungere il protocollo al privato @interfacenel .mfile e risolve le cose (almeno per me occasionalmente lo ha). Quindi sopra il tuo @implementationavere @interface MyController() <AnalyticProtocol>.
Adam

1
A volte Xcode 8 si lamenterà durante la modifica, ma quando lo crei effettivamente, seguendo questa risposta insieme ai commenti, l'errore scomparirà.
Roger Pingleton

77

Non è possibile importare l'intestazione Swift generata da Xcode nei file di intestazione objC.

Quindi, poiché desideri utilizzare il codice Swift in un file di intestazione objC, dovrai "dichiarare in avanti" le classi e i protocolli che desideri utilizzare nel file di intestazione objC, in questo modo:

@protocol AnalyticProtocol;

È ora possibile utilizzare il protocollo nella dichiarazione della classe objC:

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

Nel tuo file di implementazione (il file objC .m), puoi importare il file di intestazione Swift generato da Xcode ("ProductModuleName-Swift.h") e l'implementazione corretta AnalyticProtocolsarà ora nota al compilatore.

Questo è anche descritto nella sezione "Utilizzo di Swift da Objective-C" in Apple Docs

Si noti che XCode fornirà un avviso nel file di intestazione objC quando si utilizza il protocollo dichiarato in avanti ("Impossibile trovare la definizione del protocollo per 'AnalyticProtocol'), ma questo può essere ignorato: l'implementazione verrà trovata in fase di compilazione.


19
Perché Xcode mostra l'avviso per il protocollo mancante quando si compila e funziona correttamente? Qualche modo per rimuovere l'avviso?
Oren

Tuttavia, non è ancora possibile chiamare i metodi del protocollo su questa classe. Darà l'erroreNo visible @interface for <ClassName> declares the selector <protocolMethodName>
Elsa

produce il seguente avviso: "Impossibile trovare la definizione del protocollo per xxxx"
JAHelia

51

Per chiunque abbia semplicemente bisogno di adottare un protocollo, puoi farlo in due passaggi, senza generare avvisi o errori:

  1. Nel tuo .swiftfile, aggiungi @objcprima del nome del protocollo:

    @objc protocol AnalyticProtocol {
    
    }
  2. Nel tuo .mfile, importa l'intestazione Swift generata e adotta il protocollo in una categoria privata. (Il file di intestazione viene denominato automagicamente):

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

Questo è l'approccio consigliato da Apple. Puoi saperne di più su come combinare e abbinare Objective-C e Swift qui: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html


1
Ricevo ancora un avviso, con dichiarazione anticipata o senza. Sto usando il protocollo in un'estensione.
Cristi Băluță

Impossibile importare #import "AnalyticProtocol-Swift.h". Sembra che WwhatProtocol-Swift.h non sia generato automaticamente come hai detto.
Hlung

2
Questo ha funzionato per me; nessun altro suggerimento o risposta in questa pagina ha funzionato. Sono su Swift 4.
Poulsbo

1
Questo era l'unico modo per rimuovere l'avviso (anche se funziona quando i protocolli sono nel file di intestazione)
David P

1
Lo stesso link è disponibile tramite WebArchive: web.archive.org/web/20170310053717/https://developer.apple.com/…
Richard Topchii

3

Se stai creando un framework, il file import

#import "ProductModuleName-Swift.h"

cambia in:

#import <ProductModuleName/ProductModuleName-Swift.h>

In questo caso devi anche rendere pubblico il protocollo swift :

@objc public protocol AnalyticProtocol {
  func something();
}

3

Possiamo usare protocolli rapidi in Objective C con poche modifiche al codice. Inoltre, i protocolli dichiarati @objc consentono di avere metodi facoltativi e obbligatori senza implementazioni predefinite. Viene fornito con pro e contro.

Potremmo effettivamente rinominare il nome del protocollo in un nome più descrittivo quando lo uso nell'Obiettivo C. Uso "@objc (alias_name)".

Ecco il codice, disponiamo di un protocollo rapido con l'attributo @objc e il nome alias da utilizzare nel codice ObjC.

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

Ora lascia che farword dichiari il nostro protocollo nel file .h

@protocol ObjTableViewReloadable;

È ora possibile conformarsi a questo protocollo nel file .m e aggiungere l'implementazione dei metodi richiesti.

#import "MyApp-Swift.h"
@interface MyObjcViewController () <ObjTableViewReloadable>

grazie per aver postato questo. Sto guardando il codice legacy che è più vecchio dello sporco e se questo approccio funziona, mi farà risparmiare un sacco di dolore. :)
Adrian
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.