Wywołaj funkcję Swift z klasy Objective-C

84

Mam stary projekt Objective-C i chcę wywołać nową funkcję i obiekt Swift, utworzyłem plik „ <ProjectName>-Bridging-Header.h” i „ <ProjectName>-Swift.h

było mi łatwo wywołać funkcję ze Swift na Objective-C, ale mam problem z odwróceniem.

Utworzyłem więc prostą klasę „System.Swift”

import Foundation

@objc class System : NSObject {

    @objc func printSome() {
        println("Print line System");
    }
    
}

teraz próbuję postępować zgodnie z dokumentacją tutaj i wewnątrz <...>-Swift.hpliku, który to napisałem

@class System;

@interface System : NSObject

-(void)printSome;

@end

i zaimportowałem go do mojej klasy Objective-C. W tym momencie w mojej klasie Objective C (obecnie UIViewController) mojego kodu Objective-C próbuję wywołać metodę "printSome":

- (void)viewDidLoad
{
    [super viewDidLoad];
    System * sis = [[System alloc] init];
    [sis printSome];
    //any additional setup after loading the view from its nib.
}

teraz mam następujący błąd:

Niezdefiniowane symbole dla architektury i386: „ OBJC_CLASS $ _System”, odniesienie do: objc-class-ref w „ObjectiveC_Class_That_Call_Swift_Object” .o ld: nie znaleziono symboli dla architektury i386 clang: błąd: polecenie konsolidatora nie powiodło się z kodem zakończenia 1 (użyj -v, aby zobaczyć wywołanie)

Eloreden
źródło
Masz błąd konsolidatora. Czy to: (1) Xcode używa nazwy modułu produktu - a nie nazwy docelowej - podczas nazywania nagłówka mostkowania Objective-C i wygenerowanego nagłówka dla kodu Swift, lub (2) pamiętaj, aby zaimportować nagłówki Objective-C dla tych przed zaimportowaniem wygenerowanego przez Swift nagłówka do pliku Objective-C .m, z którego chcesz uzyskać dostęp do kodu Swift? Czy masz: #import „ProductModuleName-Swift.h” w swoim kodzie Objective-C?
petert
Tak, przeczytałem dokumentację i nazwa "ProductModelName" jest aktualna ... Jest błąd, który wewnątrz kompilacji Ustawienie modelu produktu nie został ustawiony ... Nawet go ustawiłem ...
Eloreden
@petert, czy możesz lepiej wyjaśnić drugi punkt? Napisałem wszystko, co zrobiłem ...
Eloreden,
Problem rozwiązany, dodałem nowy plik .h do mojego projektu, wywołaj <ProductModelName> -Swift.h, ale nie jest to konieczne, ponieważ kompilator po prostu tworzy ten obiekt, nawet jeśli go nie widzę. Usunąłem nowy plik, który utworzyłem i teraz wszystko działa idealnie. Tnx petert
Eloreden
Możesz odpowiedzieć na własne pytania - może to pomóc innym.
petert

Odpowiedzi:

51

Problem rozwiązany, wcześniej utworzyłem i dołączyłem nowy .hplik do mojej klasy Objective-C o nazwie<ProductModuleName>-Swift.h ale, jak odkryłem później, ten krok nie jest konieczny, ponieważ kompilator tworzy niezbędny plik jako niewidoczny.

Po prostu uwzględnij <ProductModuleName>-Swift.hw swojej klasie i powinno działać.

Eloreden
źródło
3
a co z funkcjami z parametrami?
Arnlee Vizcayno
3
Nie mogę uzyskać dostępu do funkcji Swift z parametrami i wartością zwracaną, ani nie mam dostępu do funkcji Swift bez parametrów i bez wartości zwracanej. Nie wiem dlaczego. Moja klasa Swift to obiekt NSObject, zaimportowałem framework Foundation, klasa i funkcje mają @objcprefiks. -Swift.hZostał automatycznie utworzony. Przyprawia mnie o ból głowy to, że mogę wywołać samą klasę, ale nie mogę wywołać w niej żadnej funkcji. Czy ktoś wie dlaczego?
David Gölzhäuser
4
dobry przykład na ericasadun.com/2014/08/21/…
Paul Beusterien
2
To jest <productModuleName>-.Swift.h(nie model).
SwiftArchitect
2
Jeśli nazwa produktu ma żadnych spacji w nim zastąpić je podkreślenia, jak: #import "My_Project-Swift.h".
EricRobertBrewer
41

to dziwne, ale zadziała

1) Add @objc  to  Swift class

2) Add in .m 
    #import "(ProjectName)-Swift.h"

3) Call from .h
    @class SwiftClass;

4)On SwiftClass 
   click "Command" + Left Click (Apple Documantation)

5) To see "-Swift.h" -> click "Command" + Left Click

Aplikacja wygeneruje interfejs dla tej klasy w pliku -Swift.h

Przykład: SWIFT_CLASS ("_ TtC10Project17220PLHelper") @interface PLHelper

  • (void) notifyForDownloading: (NSDictionary *) userInfo;
  • (instancetype) init OBJC_DESIGNATED_INITIALIZER; @koniec
Svitlana
źródło
Możesz także nadpisać nazwę Obj-C swojej klasy Swift za pomocą@objc (MyClassName)
nielsbot
12
Dla każdego, kto może popełnić ten sam głupi błąd co ja. W kroku 2 upewnij się, że używasz (ProjectName)-Swift.h, NIE (ClassName)-Swift.h !
Hlung
dzięki @Svitlana, niewiarygodne, zadziałało !!! Ale muszę wielokrotnie powtarzać te kroki, w tym przenosić moje dodane metody do innych miejsc w klasie.
Scofield Tran,
1
3) @class SwiftClassName;uratował mnie
Mazen Kasser
33

Załóżmy, że mamy ProjectName „MyFirstProjectOnSwift” i szybką nazwę klasy „mySwiftClass”, a klasą objectiveC jest „MyObjectiveCLass”

Następujące kroki to: -

  1. Dodaj #import „MyFirstProjectOnSwift-Swift.h” w „MyObjectiveCLass.m”

  2. Dodaj @class mySwiftClass w MyObjectiveCLass.h;

  3. Następnie w MyObjectiveCLass.m

    mySwiftClass * myClass = [mySwiftClass new]; {Call Like This w dowolnej metodzie, gdziekolwiek chcesz wywołać metodę Swift.}

  4. [myClass methodName];

Anubhav Giri
źródło
2
mySwiftClass * myClass = [mySwiftClass new] nie działa dla mnie >>>>>
Hari Narayanan
@HariNarayanan Nie powinno być, pomyśl o wyczyszczeniu danych pochodnych i ponownie otwórz projekt.
Anubhav Giri
12

Sprawdź plik -Swift.h, który ma importowany plik .m w celu-C:

#import <YourProjectName-Swift.h>

Kliknij tę linię i kliknij lewym przyciskiem myszy - Przejdź do definicji.

Ten plik powinien zostać dołączony automatycznie, a nie ręcznie.

Darius Miliauskas
źródło
2

Jeśli nadal nie widzisz swoich zajęć nawet po zaimportowaniu <ProductModuleName>-Swift.h .

Upewnij się, że Twoja klasa jest podklasą klasy natywnej (np. UIViewController) Lub przynajmniej, jeśli jest to tylko klasa użytkowa, utwórz podklasę NSObject. Twoja klasa powinna się teraz pokazać.

Bryan P
źródło
2

Mała dodatkowa wskazówka dla każdego, kto natknie się na ten post i dla kogo inne odpowiedzi nie działają: być może będziesz musiał zadeklarować swoją klasę Swift jako „publiczną”.

Przykład:

@objc public class MySwiftClass: NSObject {

Kqtr
źródło
0

Zalecanym sposobem wykonywania kodu Swift z Objective-C w projektach, które są migrowane z Obj-C do Swift, jest użycie wzorca Bridge / Proxy.

  1. Zaimplementuj mostek.

import Foundation

@objc class AnalyticsPropertyBridge: NSObject {

private var analytics: AnalyticsManager = AnalyticsManager()

@objc func refreshProperties() {

    self.analytics.set(AnalyticsProperty.clientType)
}

}

  1. Dołącz moduł wywołujący objC do pliku parasolowego (Bridging-Header):

#import "CallerModule.h"

  1. Wreszcie w pliku .m rozmówcy są dwie kwestie:

3.a Importuj plik parasolowy:

#import "MyProject-Swift.h"

3.b Wezwij most.

[[AnalyticsPropertyBridge new] refreshProperties];

Korzyści: Twój szybki kod nie zostanie zabrudzony z @objc, ponieważ kod jest wywoływany z Objc. Z biegiem czasu ObjC zostanie zmniejszony w twoim projekcie, a ostatecznie panna młoda zostanie usunięta.

Javier Calatrava Llavería
źródło
-1

Dobry artykuł, jeśli ktoś nadal ma problemy.

Konfigurowanie interoperacyjności Swift i Objective-C

  1. W tym artykule szczegółowo omówiono importowanie plików Swift do ObjC oraz plików Objc do Swift.
  2. Rozwiązuje również problem występujący zwykle, gdy nazwa projektu zawiera spację.
  3. Omawia również flagę „Nazwa modułu produktu”.
Trójząb
źródło
Chociaż może to teoretycznie odpowiedzieć na pytanie, lepiej byłoby zawrzeć tutaj zasadnicze części odpowiedzi i podać link do odniesienia.
Arghya Sadhu