Importowanie protokołu Swift w klasie Objective-C


116

Próbuję zaimportować Swift Protocol o nazwie AnalyticProtocoldo klasy Objective-C o nazwieAnalyticFactory .

protocol AnalyticProtocol
{

}

Zaczynam od istniejącego projektu Objective-C (nie utworzyłem nowego projektu Swift z xCode i nie znalazłem, jak skonfigurować mój projekt Objective-C jako projekt Swift w xCode 6 ).

W swoim pliku Swift umieściłem .hplik o nazwie, MyProjectName-Swift.hale kompilator zwrócił mi błąd informujący, że nie istnieje . Utworzyłem więc .hplik o nazwie, MyProjectName-Swift.hktóry jest właściwie pusty (nie wiem, co powinienem umieścić w środku).

W dokumentacji Apple powiedzieli, że muszę dołączyć mój .hplik nazwany MyProjectName-Swift.hdo mojego .mpliku. Ale muszę dołączyć go nie do mojego .mpliku, ale do mojego .h. Czy to może być problematyczne?

Podczas próby kompilacji pojawia się ten błąd:: 0: błąd: xxxAnalyticFactory.h: 39: nie można znaleźć deklaracji protokołu dla „AnalyticProtocol”

Oraz obciążony kod:

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

Myślę, że nie rozumiem dobrze, jak zaimportować protokół Swift do klasy Objective-C.

Czy ktoś widzi błąd w tym, co robię?


Obejrzyj wideo Integrating Swift With Objective-C z WWDC 2014. Około 30:40 w filmie opisują, jak uzyskać dostęp do protokołów Swift w klasach Objective-C.
Jamie Forrest

Odpowiedzi:


224

Musisz dodać @objcatrybut do swojego protokołu Swift w następujący sposób:

@objc protocol AnalyticProtocol {

}

25
Dziękuję za odpowiedź, ale problem nadal występuje.
Jean Lebrument

Czy możesz opublikować przykładowy projekt, który odtwarza problem?
Jamie Forrest

Dodanie @objc pomogło mi w importowaniu klas Swift do Obj-C
serg

19
@objc nie zawsze działa. Przy zgodności z protokołem czasami nie działa przy dodawaniu protokołu @interfacew .hpliku. jednak możesz dodać protokół do prywatnego @interfacew .mpliku i to naprawia pewne rzeczy (przynajmniej czasami ma dla mnie). Więc powyżej twojego @implementationmieć @interface MyController() <AnalyticProtocol>.
Adam

1
Czasami Xcode 8 będzie narzekać podczas edycji, ale kiedy faktycznie go zbudujesz, postępując zgodnie z tą odpowiedzią wraz z komentarzami, błąd zniknie.
Roger Pingleton

77

Nie jest możliwe zaimportowanie wygenerowanego przez Xcode nagłówka Swift w plikach nagłówkowych objC.

Tak więc, ponieważ chcesz użyć kodu Swift w pliku nagłówkowym objC, musisz „zadeklarować do przodu” klasy i protokoły, których chcesz użyć w pliku nagłówkowym objC, na przykład:

@protocol AnalyticProtocol;

Możesz teraz użyć protokołu w deklaracji klasy objC:

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

W pliku implementacji (plik objC .m) można zaimportować wygenerowany przez Xcode plik nagłówka Swift („ProductModuleName-Swift.h”), a AnalyticProtocolkompilator będzie teraz wiedział o poprawnej implementacji .

Jest to również opisane w sekcji „Używanie Swift z Objective-C” w Apple Docs

Zwróć uwagę, że XCode wyświetli ostrzeżenie w pliku nagłówkowym objC, gdy użyjesz protokołu zadeklarowanego do przodu („Nie można znaleźć definicji protokołu dla 'AnalyticProtocol' '), ale można to zignorować - implementację można znaleźć w czasie kompilacji.


19
Dlaczego Xcode wyświetla ostrzeżenie o braku protokołu, gdy kompiluje się i działa poprawnie? Jakiś sposób na usunięcie ostrzeżenia?
Oren

Jednak nadal nie jest możliwe wywołanie metod protokołu w tej klasie. To da błądNo visible @interface for <ClassName> declares the selector <protocolMethodName>
Elsa

generuje następujące ostrzeżenie: „Nie można znaleźć definicji protokołu dla xxxx”
JAHelia

51

Dla każdego, kto po prostu potrzebuje przyjąć protokół - możesz to zrobić w dwóch krokach, bez generowania żadnych ostrzeżeń ani błędów:

  1. W swoim .swiftpliku dodaj @objcprzed nazwą protokołu:

    @objc protocol AnalyticProtocol {
    
    }
  2. W swoim .mpliku zaimportuj wygenerowany nagłówek Swift i zastosuj protokół w prywatnej kategorii. (Plik nagłówkowy nazywa się automagicznie):

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

To jest zalecane podejście Apple. Możesz dowiedzieć się więcej o mieszaniu i dopasowywaniu Objective-C i Swift tutaj: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html


1
Nadal otrzymuję ostrzeżenie, z deklaracją wyprzedzającą lub bez. Używam protokołu w rozszerzeniu.
Cristi Băluță

Nie można zaimportować #import "AnalyticProtocol-Swift.h". Wygląda na to, że WhatersProtocol-Swift.h nie jest generowany automatycznie, jak powiedziałeś.
Hlung

2
To zadziałało dla mnie; żadne inne sugestie ani odpowiedzi na tej stronie nie zadziałały. Jestem na Swift 4.
Poulsbo

1
To był jedyny sposób na usunięcie ostrzeżenia (mimo że działa, gdy protokoły znajdują się w pliku nagłówkowym)
David P


3

Jeśli tworzysz framework, wymagany plik import

#import "ProductModuleName-Swift.h"

zmiany w:

#import <ProductModuleName/ProductModuleName-Swift.h>

W takim przypadku musisz również upublicznić protokół Swift :

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

3

Możemy używać szybkich protokołów w Objective C z kilkoma zmianami w kodzie. Ponadto zadeklarowane protokoły @objc pozwalają na opcjonalne i wymagane metody bez domyślnych implementacji. Ma wady i zalety.

W rzeczywistości moglibyśmy zmienić nazwę protokołu na bardziej opisową, gdy używam go w celu C. Używam „@objc (alias_name)”.

Oto kod, miejmy szybki protokół z atrybutem @objc i nazwą aliasu do użycia w kodzie ObjC.

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

Teraz niech Farword zadeklaruje nasz protokół w pliku .h

@protocol ObjTableViewReloadable;

Możesz teraz dostosować się do tego protokołu w pliku .m i dodać wymaganą implementację metod.

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

Dziękuję za wysłanie tego. Patrzę na stary kod, który jest starszy niż brud i jeśli to podejście zadziała, zaoszczędzi mi to mnóstwo bólu. :)
Adrian
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.