Czy można używać Enum Swift w Obj-C?


145

Próbuję przekonwertować część mojej klasy Obj-C na Swift. I kilka innych klas Obj-C nadal używających enum w tej przekonwertowanej klasie. Szukałem w dokumentach przedpremierowych i nie mogłem go znaleźć, a może przegapiłem. Czy istnieje sposób na użycie Swift enum w klasie Obj-C? Lub link do dokumentu tego wydania?

W ten sposób zadeklarowałem wyliczenie w moim starym kodzie Obj-C i nowym kodzie Swift.

mój stary kod Obj-C:

typedef NS_ENUM(NSInteger, SomeEnum)
{
    SomeEnumA,
    SomeEnumB,
    SomeEnumC
};

@interface SomeClass : NSObject

...

@end

mój nowy kod Swift:

enum SomeEnum: NSInteger
{
    case A
    case B
    case C
};

class SomeClass: NSObject
{
    ...
}

Aktualizacja: z odpowiedzi. Nie można tego zrobić w Swift starszej wersji niż 1.2. Ale według tego oficjalnego bloga Swift . W Swift 1.2, który został wydany wraz z XCode 6.3, możesz użyć Swift Enum w Objective-C, dodając @objcprzedenum


Naprawdę nie ma potrzeby zmiany istniejącego kodu. Aby zapoznać się z interakcją między Swift i Objective-C, obejrzyj filmy WWDC.
gnasher729

Chcę tylko sprawdzić, czy mój projekt nadal działa, czy w przyszłości będzie w moim projekcie klasa szybka, ale nie mogę dowiedzieć się, jaką klasę powinienem dodać, aby ją przetestować. Więc zamiast tego konwertuję stary. W każdym razie dziękuję za pomoc.
myLifeasdog

Odpowiedzi:


226

Od wersji Swift 1.2 (Xcode 6.3) możesz. Po prostu poprzedź deklarację wyliczenia za pomocą@objc

@objc enum Bear: Int {
    case Black, Grizzly, Polar
}

Bezwstydnie zaczerpnięte z Swift Blog

Uwaga: nie działa to w przypadku wyliczeń typu String lub wyliczeń z powiązanymi wartościami. Twoje wyliczenie będzie musiało być powiązane


W Objective-C to by wyglądało

Bear type = BearBlack;
switch (type) {
    case BearBlack:
    case BearGrizzly:
    case BearPolar:
       [self runLikeHell];
}

8
wielkie dzięki za zwrócenie na to uwagi ... zauważ, że w celu-c, chociaż wartości wyliczenia będą call BearBlack, BearGrizzlyi BearPolar!
nburk

1
To ma sens, nie? Zwłaszcza jeśli spojrzeć na to, jak jest tłumaczone z obj-c na swift. @Nburk
Daniel Galasko

1
Tak, to działa. Jednak przynajmniej w moim przypadku należało dodać atrybut „public” do wyliczenia, aby był dostępny po stronie Objective-C projektu, na przykład: "@objc public enum Bear: Int"
Pirkka Esko

Szkoda, że ​​nie widzę żadnych dowodów na to, że wartości powiązane ze Swift enum są możliwe. pobożne życzenia
finneycanhelp

2
@AJit, dlaczego chcesz to zrobić? Po prostu dodaj wyliczenie do własnego nagłówka i zaimportuj to w nagłówku mostkującym, w przeciwnym razie jest dostępne wyłącznie w języku Swift
Daniel Galasko,

31

Aby rozwinąć wybraną odpowiedź ...

Możliwe jest udostępnianie wyliczeń w stylu Swift między Swift i Objective-C przy użyciu NS_ENUM().

Wystarczy je zdefiniować w kontekście Objective-C przy użyciu NS_ENUM()i są udostępniane za pomocą notacji kropkowej Swift.

Od używania Swift z kakao i Objective-C

Swift importuje jako wyliczenie Swift dowolne wyliczenie w stylu C oznaczone NS_ENUMmakrem. Oznacza to, że przedrostki nazw wartości wyliczenia są obcinane, gdy są importowane do Swift, niezależnie od tego, czy są zdefiniowane w strukturach systemu, czy w kodzie niestandardowym.

Cel C

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
   UITableViewCellStyleDefault,
   UITableViewCellStyleValue1,
   UITableViewCellStyleValue2,
   UITableViewCellStyleSubtitle
};

Szybki

let cellStyle: UITableViewCellStyle = .Default

Otrzymuję komunikat UITableViewCellStyle „definicja funkcji jest tu niedozwolona”, co robię źle? Oczywiście mam różne nazwy, a nie UITableViewCellStyle.
Cristi Băluță

1
Jak zauważono w odpowiedzi pana Galasko poniżej, Swift 1.2 umożliwia zdefiniowanie wyliczeń w języku Swift i dostępne w Obj-c. Ten styl definicji, mianowicie NS_ENUM, nadal działa w Obj-c, ale od wersji 1.2 Swift możesz użyć dowolnej opcji.
SirNod

Znalazłem problem z wyliczeniami ObjC w Swift: nie są one dostępne. W fragmencie takim jak if let a = MyEnum(rawValue: 12345)gdzie 12345 nie jest częścią tego wyliczenia, wynik nie jest opcjonalny, ale jakieś nieprawidłowe wyliczenie.
biografia

30

Z przewodnika Używanie Swift z kakao i Objective-C :

Klasa lub protokół Swift musi być oznaczony atrybutem @objc, aby był dostępny i użyteczny w Objective-C. […]

Będziesz mieć dostęp do wszystkiego w klasie lub protokole, który jest oznaczony atrybutem @objc, o ile jest zgodny z Objective-C. Wyklucza to funkcje dostępne tylko w języku Swift, takie jak wymienione tutaj:

Krotki generyczne / wyliczenia zdefiniowane w języku Swift / Struktury zdefiniowane w funkcjach Swift / najwyższego poziomu zdefiniowane w zmiennych Swift / Global zdefiniowane w Swift / Typealiases zdefiniowane w wariadyce w stylu Swift / Swift / Typy zagnieżdżone / Funkcje Curried

Więc nie, nie możesz użyć wyliczenia Swift w klasie Objective-C.


2
Czy jest w pobliżu praca? Chodzi mi o to, że jeśli utworzę klasę Swift i absolutnie potrzebuję wyliczenia. Jak mogę sprawić, by to wyliczenie było również użyteczne w Objective-C?
Raul Lopez

4
@RaulLopezVillalpando Jeśli wiesz, że będziesz współpracować z Objective-C, powinieneś zadeklarować wyliczenie w Objective-C i pozwolić, aby oba języki je współdzieliły.
Gregory Higley

3
„Tak, więc stworzyliśmy ten most, aby pomóc Ci przejść na Swift, ale jest bezużyteczny, jeśli chcesz używać czegoś fajnego, takiego jak Enums, Structs, Generics ... Więc jest to ...”
Kevin R

22
TA ODPOWIEDŹ JUŻ NIE JEST WAŻNA !! od Xcode 6.3 / Swift 1.2, wyliczenia Swift mogą być również używane w ramach objective-c, @objcjak @DanielGalasko wskazał w swojej odpowiedzi poniżej !!!
nburk

9
Dla wyjaśnienia powyższego komentarza, cytując aktualny tekst dokumentacji w wersji Swift 2.1 , „Wyliczenia zdefiniowane w języku Swift bez typu wartości surowej Int ”. Tak więc, jeśli twoje wyliczenie w Swift jest zadeklarowane z typem wartości surowej Int @obj enum MyEnum: Int, będzie działać dobrze na plikach Objective-C, jak wspomniano wcześniej. Jeśli twoje wyliczenie jest zadeklarowane z innym surowym typem wartości, takim jak @obj enum MyOtherEnum: String, nie będziesz mógł go użyć w plikach Objective-C
jjramos

7

Swift 4.1, Xcode 9.4.1:

1) Swift wyliczenie musi mieć prefiks @objci być Inttypu:

// in .swift file:
@objc enum CalendarPermission: Int {
    case authorized
    case denied
    case restricted
    case undetermined
}

2) Nazwa celu-C to nazwa wyliczenia + nazwa przypadku, np . CalendarPermissionAuthorized:

// in .m file:
// point to something that returns the enum type (`CalendarPermission` here)
CalendarPermission calPermission = ...;

// use the enum values with their adjusted names
switch (calPermission) {
    case CalendarPermissionAuthorized:
    {
        // code here
        break;
    }
    case CalendarPermissionDenied:
    case CalendarPermissionRestricted:
    {
        // code here
        break;
    }
    case CalendarPermissionUndetermined:
    {
        // code here
        break;
    }
}

I oczywiście pamiętaj, aby zaimportować swój nagłówek mostkowania Swift jako ostatni element na liście importu pliku Objective-C:

#import "MyAppViewController.h"
#import "MyApp-Swift.h"

dlaczego MyApp-Swift miałby być ostatni?
Paul T.

@PaulT. : prawdopodobnie ma to związek z kolejnością przetwarzania. Spróbuj umieścić go w innym miejscu, a zobaczysz, że nie zadziała.
leanne

Sprawdziłem, w moim obecnym projekcie prawie we wszystkich plikach jest na końcu sekcji importu, ale w kilku plikach nie jest na końcu i projekt działa. może być w nowym Xcode to działa? Nie mogę tego teraz sprawdzić, ponieważ kompilacja mojego obecnego projektu zajmuje wieki :), ale sprawdzę to później
Paul T.

2

Jeśli wolisz zachować kody ObjC bez zmian, możesz dodać do projektu plik nagłówka pomocnika:

Swift2Objc_Helper.h

w pliku nagłówkowym dodaj ten typ wyliczenia:

typedef NS_ENUM(NSInteger, SomeEnum4ObjC)
{
   SomeEnumA,
   SomeEnumB
};

W pliku .m może znajdować się inne miejsce na dokonanie zmiany: włączenie ukrytego pliku nagłówkowego:

#import "[YourProjectName]-Swift.h"

zastąp [YourProjectName] nazwą swojego projektu. Ten plik nagłówkowy uwidacznia wszystkie klasy @objc zdefiniowane w języku Swift, wyliczenia w ObjC.

Możesz otrzymać ostrzeżenie o niejawnej konwersji z typu wyliczenia ... Jest OK.

Przy okazji, możesz użyć tego pliku pomocniczego nagłówka, aby zachować niektóre kody ObjC, takie jak stałe #define.


0

Jeśli (tak jak ja) naprawdę chcesz używać wyliczeń typu String, możesz stworzyć wyspecjalizowany interfejs dla Objective-c. Na przykład:

enum Icon: String {
    case HelpIcon
    case StarIcon
    ...
}

// Make use of string enum when available:
public func addIcon(icon: Icon) {
    ...
}

// Fall back on strings when string enum not available (objective-c):
public func addIcon(iconName:String) {
    addIcon(Icon(rawValue: iconName))
}

Oczywiście nie zapewni ci to wygody autouzupełniania (chyba że zdefiniujesz dodatkowe stałe w środowisku celu-c).


0

to może trochę bardziej pomóc

Opis problemu : - Mam wyliczenie w klasie swift, do której uzyskuję dostęp z innych klas swift, a teraz muszę uzyskać do niego dostęp z mojej jednej z obiektywnych klas C.

Przed uzyskaniem do niego dostępu z klasy celu-c: -

enum NTCType   {
    case RETRYNOW
    case RETRYAFTER
}
 var viewType: NTCType? 

Zmiany dotyczące dostępu do niego z obiektywnej klasy c

@objc  enum NTCType :Int  {
    case RETRYNOW
    case RETRYAFTER
}

i dodaj funkcję, aby przekazać ją do wartości

  @objc  func setNtc(view:NTCType)  {
        self.viewType = view; // assign value to the variable
    }

0

Po zbadaniu tego wciąż znajdowałem tylko częściowe odpowiedzi, więc stworzyłem cały przykład aplikacji Swift połączonej z celem C, która ma wyliczenia Swift używane przez kod Objective C i wyliczenia Objective C używane przez kod Swift. Jest to prosty projekt Xcode, który możesz uruchomić i eksperymentować. Został napisany przy użyciu Xcode 10.3 ze Swift 5.0

Przykładowy projekt


Nie widzę, gdzie twój projekt używa szybkiego wyliczenia w celu C. Również w definicji szybkiego wyliczenia enum SwAnimalbrakuje wiodącego@obj
oliolioli

0

W przypadku, gdy próbujesz obserwować wyliczenie, które wygląda następująco:

enum EnumName: String {
    case one = "One"
    case two = "Two"
}

to obejście pomogło mi.

Obserwowalna klasa:

  • Stwórz @objc dynamic var observable: String?
  • utwórz swoją instancję wyliczenia w następujący sposób:

    private var _enumName: EnumName? {
        didSet {
            observable = _enumName!.rawValue
        }
    }

Klasa obserwatora:

  • Stwórz private var _enumName: EnumName?
  • Stwórz private let _instance = ObservableClass()
  • Stwórz

    private var _enumObserver: NSKeyValueObservation = _instance.observe(\.observable, options: .new, changeHandler: { [weak self] (_, value) in
        guard let newValue = value.newValue else { return }
        self?._enumName = EnumName(rawValue: period)!
    })

To jest to. Teraz za każdym razem, gdy zmieniasz_enumName klasę w obserwowalnej klasie, odpowiednia instancja w klasie obserwatora zostanie również natychmiast zaktualizowana.

Jest to oczywiście uproszczona implementacja, ale powinna dać ci wyobrażenie, jak obserwować właściwości niezgodne z KVO.

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.