Czy kod Objective-C może wywołać szybkie rozszerzenie w Class?

94

Przeszukałem kilka postów, myślę, że nie mogę napisać rozszerzenia w ramach szybkiego i wywołać go z kodu Objective-C, prawda?

@objc podobnie jak atrybuty obsługują tylko metody, klasy, protokoły?

sprhawk
źródło
1
Dlaczego po prostu nie spróbujesz?
MA
7
ide narzekał błąd, ale chcę uzyskać ostateczną odpowiedź.
sprhawk,

Odpowiedzi:

84

Możesz napisać rozszerzenie Swift i używać go w kodzie Objective-C. Przetestowano za pomocą XCode 6.1.1.

Wszystko, co musisz zrobić, to:

  • utwórz rozszerzenie w Swift (bez @objcadnotacji)

  • #import "ProjectTarget-Swift.h" w klasie Objective-C (gdzie „ProjectTarget” reprezentuje cel XCode, z którym jest skojarzone rozszerzenie Swift)

  • wywołać metody z rozszerzenia Swift

Aktualizacja: Jak wspomniano @Rizwan Ahmed, musisz dodać @objcadnotację:

Od wersji Swift 4.0.3 adnotacja @objc jest potrzebna, jeśli chcesz używać rozszerzenia w plikach klasy Objective C.

marius bardan
źródło
6
Zrobiłem dokładnie to, ale nadal jest to błąd czasu kompilacji. Hmmm. EDYCJA: zaimportowałem mój nagłówek pomostowy zamiast „ProjectTarget-Swift.h”. Der.
Jason Renaldo
Oba są nagłówkami mostkującymi. Różnica polega na tym, że jeden służy do używania kodu Swift w ObjC, a drugi do używania kodu ObjC w Swift. Nagłówek Swift jest niewidoczny. Drugi powinien być zarządzany przez Ciebie.
marius bardan
William Hu, zobacz odpowiedź Mclaughlinja!
appleitung
39
Od wersji Swift 4.0.3 adnotacja @objc jest potrzebna, jeśli chcesz używać rozszerzenia w plikach klasy Objective C.
Rizwan Ahmed
69

I okazało się, że w Swift 4.0 musiałem dodać @objcprzed moim rozszerzeniem słów kluczowych w celu metod przedłużających Swift, by stać się widoczny przez instancji objc klasie byłem rozciągającej.

W skrócie:

Konfiguracja konfiguracji plików:

CustomClass.h
CustomClass.m
CustomClassExtension.swift

W CustomClassExtension:

@objc extension CustomClass
{
    func method1() 
    {
        ...
    }
}

W moim AppDelegate.m:

self.customClass = [[CustomClass alloc] init];
[self.customClass method1];
Andrey P.
źródło
2
Jeśli metoda używa typów ogólnych, nie może być używana przez Objective-C i musisz dodać @nonobjcadnotację.
Thomas W
Tylko uwaga, @objcMembers nie działa w tym przypadku. Nie wiem dlaczego .. :-(
Raunak
46

To rozwiązanie działa dla Swift 2.2 i Swift 3 . Zauważ, że tylko rozszerzenia dla klas (nie dla struktur lub wyliczeń) będą dostępne z Objective-C.

import UIKit

extension UIColor {

    //Custom colours
    class func otherEventColor() -> UIColor {
        return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
    }
}

Następnie #import „ProductModuleName-Swift.h” w pliku ObjC.

Szybki 4

extension UIColor {

    // As of Swift 4.0.3, the @objc annotation is needed if you want to use the extension in Objective-C files
    @objc
    class func otherEventColor() -> UIColor {
        return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
    }
}
Foti Dim
źródło
To nie jest "YourProjectsNameHere ...", ale raczej "YourTargetsNameHere ...": aby udostępnić cele, musisz zablokować je na imię: dr2050.postach.io/post/ ...
Dan Rosenstark
1
@DanRosenstark Masz rację. Zmieniam go na „ProductModuleName-Swift.h”, jak sugeruje Apple: developer.apple.com/library/ios/documentation/Swift/Conceptual/ ...
Foti Dim
1
Działa dobrze dla szybkiej 3.
Viktor Kucera
Czy istnieje powód, dla którego twierdzisz, że publicjest potrzebny? U mnie działa dobrze bez publicmodyfikatora. Czy zakładamy, że rozszerzenie nie znajduje się w tym samym projekcie, ale jest importowane z innego projektu?
Lee Kang
Czy muszę używać nagłówka mostkującego?
jegadeesh
42

Jak opisano w innych odpowiedziach, importowanie wygenerowanego nagłówka Swift działa w większości przypadków .

Wyjątkiem jest sytuacja, gdy kategoria jest zdefiniowana dla typu pomostowego (tj. Rozszerzenie jest zdefiniowane na, Stringa nie NSString). Kategorie te nie zostaną automatycznie połączone z ich odpowiednikami w celu C. Aby to obejść, musisz albo użyć typu Objective-C (i rzutować wartość zwracaną w kodzie Swift za pomocą as String), albo zdefiniować rozszerzenie dla obu typów Swift i Objective-C.

mclaughlinj
źródło
2
Dodając do powyższej odpowiedzi, powinieneś upublicznić swoje szybkie rozszerzenie i ustawić jego typ jako NSString np public extension NSString. Jeśli pojawi się nierozwiązany identyfikator lub podobny błąd w czasie kompilacji, możesz ponownie rzutować z powrotem na String, np., let sVal = self as StringA następnie wywołać niezbędny kod nasVal
RunLoop
@RunLoop właściwie nie potrzebujesz public, będzie działać bez specyfikatora zakresu. I to (mam na myśli eksport do Obj-C) nie działa dla Stringsów, ponieważ są to struktury, a nie klasy i są dostępne tylko w Swift. Więc tak - możesz napisać rozszerzenie dla NSString i użyć rzutowania lub napisać rozszerzenia, jak mclaughlinjpowiedziałem, zarówno dla klasy NSString, jak i struktury String
Alex Nazarsky
3

Zaimportuj nagłówek „#import” ProductModuleName-Swift.h ”do pliku objective-c i dodaj @objc przed swoim zakresem w pliku swift. Będzie działać dobrze w Swift 4.2 i Swift 5

Ranjani
źródło