Можно ли использовать Swift Enum в Obj-C?

149

Я пытаюсь преобразовать некоторые из моих классов Obj-C в Swift. И некоторые другие классы Obj-C все еще используют enum в этом преобразованном классе. Я искал в предварительной документации и не нашел, а может, пропустил. Есть ли способ использовать Swift enum в классе Obj-C? Или ссылку на документ этого вопроса?

Вот как я объявил свое перечисление в моем старом коде Obj-C и новом коде Swift.

мой старый код Obj-C:

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

@interface SomeClass : NSObject

...

@end

мой новый код Swift:

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

class SomeClass: NSObject
{
    ...
}

Обновление: Из ответов. Это невозможно сделать в Swift более ранней версии, чем 1.2. Но согласно этому официальному блогу Swift . В Swift 1.2, выпущенном вместе с XCode 6.3, вы можете использовать Swift Enum в Objective-C, добавив @objcпередenum

myLifeasdog
источник
На самом деле нет необходимости изменять существующий код. Чтобы узнать о взаимодействии Swift и Objective-C, посмотрите видеоролики WWDC.
gnasher729
Я просто хочу проверить, работает ли мой проект, если в будущем в моем проекте будет быстрый класс, но я не могу понять, какой класс мне добавить для его тестирования. Поэтому вместо этого я переделываю старую. В любом случае спасибо за вашу помощь.
myLifeasdog

Ответы:

231

Начиная со Swift версии 1.2 (Xcode 6.3) вы можете. Просто добавьте к объявлению перечисления префикс@objc

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

Бесстыдно взято из блога Swift

Примечание. Это не сработает для перечислений String или перечислений со связанными значениями. Ваше перечисление должно быть привязано к Int


В Objective-C это будет выглядеть как

Bear type = BearBlack;
switch (type) {
    case BearBlack:
    case BearGrizzly:
    case BearPolar:
       [self runLikeHell];
}
Даниэль Галаско
источник
8
Большое спасибо за указание на это ... обратите внимание, что в objective-c, хотя значения перечисления будут вызваны BearBlack, BearGrizzlyи BearPolar!
nburk
1
Нет в этом смысла? Особенно если вы посмотрите, как это переводится из obj-c в swift .. @nburk
Даниэль Галаско
1
Да, это работает. Однако, по крайней мере, в моем случае в перечисление необходимо было добавить атрибут «public», чтобы он был доступен на стороне проекта Objective-C, например: «@objc public enum Bear: Int»
Пиркка Эско
Жаль, что я не вижу никаких доказательств того, что значения, связанные с Swift enum, возможны. принятие желаемого за действительное
Finneycanhelp
2
@AJit, зачем тебе это делать? Просто добавьте перечисление в его собственный заголовок и импортируйте его в заголовок моста, иначе оно будет эксклюзивным для Swift
Даниэль Галаско
31

Чтобы развернуть выбранный ответ ...

Можно совместно использовать перечисления стиля Swift между Swift и Objective-C, используя NS_ENUM().

Их просто нужно определить в контексте Objective-C, используя, NS_ENUM()и они доступны с использованием точечной нотации Swift.

От использования Swift с какао и Objective-C

Swift импортирует в качестве перечисления Swift любое перечисление в стиле C, помеченное NS_ENUMмакросом. Это означает, что префиксы для имен значений перечисления усекаются при импорте в Swift, независимо от того, определены ли они в системных фреймворках или в пользовательском коде.

Цель-C

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

Swift

let cellStyle: UITableViewCellStyle = .Default
SirNod
источник
Я получаю UITableViewCellStyle «определение функции здесь запрещено», что я делаю не так? Конечно, у меня разные имена, а не UITableViewCellStyle.
Cristi Băluță
1
Как отмечено в ответе г-на Галаско ниже, Swift 1.2 позволяет определять перечисления в Swift и быть доступными в Obj-c. Этот стиль определения, а именно NS_ENUM, по-прежнему работает в Obj-c, но начиная с версии Swift 1.2 вы можете использовать любой вариант.
SirNod
Я обнаружил, что в Swift есть проблема с перечислениями ObjC: они не работают. Во фрагменте, например, if let a = MyEnum(rawValue: 12345)где 12345 не является частью этого перечисления, результат не является необязательным, а является неким недопустимым перечислением.
биография
30

Из руководства Использование Swift с Какао и Objective-C :

Класс или протокол Swift должны быть помечены атрибутом @objc, чтобы их можно было использовать в Objective-C. [...]

У вас будет доступ ко всему в рамках класса или протокола, помеченного атрибутом @objc, если он совместим с Objective-C. Это исключает функции только для Swift, например перечисленные здесь:

Обобщенные кортежи / перечисления, определенные в Swift / Структуры, определенные в Swift / Функции верхнего уровня, определенные в Swift / Глобальные переменные, определенные в Swift / Typealiases, определенные в Swift / вариативности стиля Swift / Вложенные типы / функции карри

Итак, нет, вы не можете использовать перечисление Swift в классе Objective-C.

hpique
источник
2
Есть ли обходной путь? Я имею в виду, если я создам класс Swift, и мне абсолютно необходимо перечисление. Как сделать так, чтобы это перечисление можно было использовать и в Objective-C?
Рауль Лопес,
4
@RaulLopezVillalpando Если вы знаете, что собираетесь взаимодействовать с Objective-C, то вам следует объявить перечисление в Objective-C и позволить обоим языкам совместно использовать его.
Грегори Хигли
3
«Да, мы сделали этот мост, чтобы помочь вам перейти на Swift, но он бесполезен, если вы хотите использовать что-то классное, например Enums, Structs, Generics ... Так вот что ...»
Кевин Р.
22
ЭТОТ ОТВЕТ НЕТ ДЕЙСТВИТЕЛЬНО! начиная с Xcode 6.3 / Swift 1.2, перечисления Swift также можно использовать в objective-c, используя @objcкак @DanielGalasko указал в своем ответе ниже !!!
nburk
9
Чтобы прояснить приведенный выше комментарий, процитируем текущий текст документации по Swift 2.1 : «Перечисления, определенные в Swift без типа необработанного значения Int ». Итак, если ваше перечисление в Swift объявлено с типом необработанного значения Int, поскольку @obj enum MyEnum: Intоно будет нормально работать с файлами Objective-C, как упоминалось ранее. Если ваше перечисление объявлено с другим типом необработанного значения, например @obj enum MyOtherEnum: String, вы не сможете использовать его в файлах Objective-C
jjramos
9

Swift 4.1, Xcode 9.4.1:

1) Swift enum должен иметь префикс @objcи иметь Intтип:

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

2) Имя Objective-C - это имя перечисления + имя случая, например 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;
    }
}

И, конечно же, не забудьте импортировать заголовок моста Swift в качестве последнего элемента в списке импорта файла Objective-C:

#import "MyAppViewController.h"
#import "MyApp-Swift.h"
Лэнн
источник
почему MyApp-Swift должен быть последним?
Пол Т.
@PaulT. : наверное, дело в порядке обработки. Попробуйте положить его в другое место, и вы увидите, что это не сработает.
Линн,
Я проверил, в моем текущем проекте почти во всех файлах он находится в конце раздела импорта, но в некоторых файлах он не в конце, и проект работает. может в новом Xcode все работает? Я не могу проверить это сейчас, потому что мой текущий проект требует времени для компиляции :), но я собираюсь проверить это позже
Пол Т.
2

Если вы предпочитаете сохранять коды ObjC как есть, вы можете добавить в свой проект вспомогательный файл заголовка:

Swift2Objc_Helper.h

в файле заголовка добавьте этот тип перечисления:

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

В вашем .m файле может быть другое место для внесения изменений: для включения скрытого файла заголовка:

#import "[YourProjectName]-Swift.h"

замените [YourProjectName] названием вашего проекта. Этот файл заголовка предоставляет все классы @objc, определенные Swift, перечисляемые в ObjC.

Вы можете получить предупреждающее сообщение о неявном преобразовании из типа перечисления ... Это нормально.

Кстати, вы можете использовать этот вспомогательный файл заголовка для хранения некоторых кодов ObjC, таких как константы #define.

David.Chu.ca
источник
0

Если вы (как и я) действительно хотите использовать перечисления String, вы можете создать специализированный интерфейс для objective-c. Например:

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))
}

Конечно, это не даст вам удобства автозаполнения (если вы не определите дополнительные константы в среде objective-c).

Лукас Калински
источник
0

это может помочь немного больше

Постановка задачи : - У меня есть перечисление в быстром классе, к которому я обращаюсь из других быстрых классов, и теперь мне нужно получить доступ к нему из моего одного из объективных классов C.

Перед доступом к нему из класса objective-c: -

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

Изменения для доступа к нему из объектного класса c

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

и добавьте функцию, чтобы передать ей значение

  @objc  func setNtc(view:NTCType)  {
        self.viewType = view; // assign value to the variable
    }
Анураг Бхакуни
источник
0

Изучив это, я продолжал находить только частичные ответы, поэтому я создал полный пример приложения Swift, связанного с Objective C, которое имеет перечисления Swift, используемые кодом Objective C, и перечисления Objective C, используемые кодом Swift. Это простой проект Xcode, который можно запускать и экспериментировать. Он был написан с использованием Xcode 10.3 со Swift 5.0

Пример проекта

user3288724
источник
Я не вижу, где ваш проект использует быстрое перечисление в Objective C. Также в определении быстрого перечисления enum SwAnimalотсутствует ведущий@obj
oliolioli
0

Если вы пытаетесь наблюдать перечисление, которое выглядит так:

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

этот обходной путь мне помог.

Наблюдаемый класс:

  • Создайте @objc dynamic var observable: String?
  • создайте свой экземпляр перечисления следующим образом:

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

Класс наблюдателя:

  • Создайте private var _enumName: EnumName?
  • Создайте private let _instance = ObservableClass()
  • Создайте

    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)!
    })
    

Тогда это. Теперь каждый раз, когда вы меняете _enumNameв наблюдаемом классе, соответствующий экземпляр в классе наблюдателя также будет немедленно обновляться.

Это, конечно, упрощенная реализация, но она должна дать вам представление о том, как наблюдать несовместимые с KVO свойства.

Гаспер Дж.
источник