Чи можливо використовувати Enum Swift в Obj-C?


145

Я намагаюся перетворити частину мого класу Obj-C в Swift. І деякі інші класи Obj-C, які все ще використовують enum у цьому перетвореному класі. Я шукав Документи перед випуском і не зміг його знайти або, можливо, пропустив. Чи є спосіб використання перерахунку Swift в класі Obj-C? Або посилання на документ цього випуску?

Ось як я заявив про перерахунок у своєму старому коді Obj-C та новому коді Swift.

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

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

@interface SomeClass : NSObject

...

@end

мій новий код Свіфта:

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

class SomeClass: NSObject
{
    ...
}

Оновлення: з відповідей. Це не можна зробити в Swift старшій версії 1.2. Але відповідно до цього офіційного Swift Blog . У Swift 1.2, який вийшов разом із XCode 6.3, ви можете використовувати Swift Enum в Objective-C, додавши @objcпередenum


Насправді не потрібно змінювати існуючий код. Для взаємодії між Swift та Objective-C дивіться відеозаписи WWDC.
— gnasher729

Я просто хочу перевірити, чи мій проект все ще працює, чи буде в моєму проекті швидкий клас у майбутньому, але я не можу зрозуміти, який клас слід додати, щоб перевірити його. Отже, я замість цього перетворюю стару. У будь-якому випадку, дякую за вашу допомогу.
— myLifeasdog

Відповіді:


226

З версією Swift 1.2 (Xcode 6.3) ви можете. Просто додайте до декларації перерахунок@objc

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

Безсоромно взято із блогу Swift

Примітка. Це не буде працювати для String enums або enums з пов'язаними значеннями. Вашій пережитці потрібно буде зв'язати між собою


У Objective-C це виглядатиме так

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

8
велике спасибі за його вказівку ... зауважте, що в aim-c хоча значення перерахунків будуть називатися BearBlack, BearGrizzlyі BearPolar!
— nburk

1
Це має сенс ні? Тим більше, коли дивишся, як це перекладається з obj-c на стрімкий .. @nburk
— Даніель Галаско

1
Так, це працює. Однак принаймні в моєму випадку до перерахунку потрібно було додати атрибут "public", щоб він був доступний на стороні "Objective-C", наприклад: "@objc public enum Bear: Int"
— Pirkka Esko

Шкода, що я не бачу жодних доказів того, що можливі значення, пов'язані з перерахуванням Swift. бажане мислення
— finneycanhelp

2
@AJit, чому б ти хотів це зробити? Просто додайте перерахунок до власного заголовка та імпортуйте, що в мостовому заголовку в іншому випадку це ексклюзивно для Swift
— Даніель Галаско

31

Щоб розгорнути вибрану відповідь ...

Можливо поділити переліки стилів Swift між Swift та Objective-C за допомогою NS_ENUM().

Їх просто потрібно визначити в контексті Objective-C, використовуючи їх, NS_ENUM()і вони стануть доступними, використовуючи позначення крапок Swift.

Від використання Swift з какао та Objective-C

Swift імпортує як перелік Swift будь-яке перерахування в стилі С, позначене NS_ENUMмакросом. Це означає, що префікси до імен значень перерахування обрізаються, коли вони імпортуються в Swift, незалежно від того, чи визначені вони в системних рамах чи у власному коді.

Ціль-С

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

Швидкий

let cellStyle: UITableViewCellStyle = .Default

Я отримую на UITableViewCellStyle "визначення тут заборонено", що я роблю неправильно? Звичайно, у мене різні імена не UITableViewCellStyle.
— Крісті Балуша

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 / Вкладені типи / Curried функції

Отже, ні, ви не можете використовувати перерахунок Swift у класі Objective-C.


2
Чи існує рішення? Я маю на увазі, якщо я створю клас Swift і мені абсолютно потрібен перерахунок. Як я можу зробити так, щоб перерахунок був застосований і в Objective-C?
— Раул Лопес

4
@RaulLopezVillalpando Якщо ви знаєте, що будете взаємодіяти з Objective-C, то вам слід оголосити перерахування в Objective-C і дозволити їм використовувати обидві мови.
— Gregory Higley

3
"Так, ми зробили цей міст, щоб допомогти вам перейти до Свіфта, але марно, якщо ви хочете використовувати щось круте, як Enums, Structs, Generics ... Так ось це ..."
— Кевін R,

22
ЦЕ ВІДПОВІДЬ НІКОЛИ ДІЛЬНІСТЬ !! оскільки Xcode 6.3 / Swift 1.2, перерахунки Swift можна також використовувати в межах @objcObje -c, як @DanielGalasko вказав у своїй відповіді нижче !!!
— nburk

9
Просто для уточнення вищезазначеного коментаря, цитуючи поточний текст у документації станом на Swift 2.1 , "Перерахунки, визначені в Swift без типу внутрішнього значення ". Отже, якщо ваш перерахунок у Swift оголошений з типом типу "Int raw", як у @obj enum MyEnum: Intньому, він буде добре працювати з файлами Objective-C, як згадувалося раніше. Якщо ваш enum оголошений з іншим типом необробленого значення, наприклад @obj enum MyOtherEnum: String, ви не зможете використовувати його у файлах Objective-C
— jjramos

7

Swift 4.1, Xcode 9.4.1:

1) Швидкий перелік має бути з префіксом @objcта Intнабрати:

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

2) Назва Objective-C - це ім'я enum + ім'я справи, наприклад 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 Bridge, як останній елемент у списку імпорту файлу Objective-C:

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

чому MyApp-Swift повинен бути останнім?
— Пол Т.

@PaulT. : ймовірно, має відношення до порядку обробки. Спробуйте помістити його в інше місце, і ви побачите, що це не спрацює.
— leanne

Я перевірив, що в моєму поточному проекті майже у всіх файлах він знаходиться в кінці розділу імпорту, але в декількох файлах він не в кінці, і проект працює. може бути, в новому Xcode він працює? Я не можу перевірити це зараз, оскільки для мого поточного проекту потрібні віки для складання :), але я перевіряю його пізніше
— Пол Т.

2

Якщо ви віддаєте перевагу зберігати коди ObjC такими, якими вони є, ви можете додати файл допоміжного заголовка у свій проект:

Swift2Objc_Helper.h

у файл заголовка додайте цей тип перерахунку:

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

У вашому .m-файлі може бути інше місце, щоб внести зміни: включити прихований файл заголовка:

#import "[YourProjectName]-Swift.h"

замініть [YourProjectName] назвою вашого проекту. Цей заголовок викриває всі визначені Swift класи @objc, перераховує ObjC.

Ви можете отримати попереджувальне повідомлення про неявну конверсію від типу перерахування ... Це нормально.

До речі, ви можете використовувати цей помічник-файл заголовка, щоб зберегти деякі коди ObjC, такі як #define константи.


0

Якщо ви (як я) дуже хочете скористатись String enums, ви можете створити спеціалізований інтерфейс для 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))
}

Звичайно, це не дасть вам зручності автоматичного заповнення (якщо ви не визначите додаткові константи в середовищі target-c).


0

це може допомогти трохи більше

Постановка проблеми : - У мене є перелік у швидкому класі, до якого я отримую доступ до інших швидких класів, і тепер мені потрібно отримати доступ до нього з одного з об'єктивних класів С.

Перш ніж отримати доступ до нього з класу Obje-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, з'єднаного з об'єктом C, який має перерахунки Swift, використовувані кодом Objective C та перерахунками Objective C, використовуваними кодом Свіфта. Це простий проект Xcode, з яким можна запускати та експериментувати. Він був написаний за допомогою Xcode 10.3 за допомогою Swift 5.0

Приклад проекту


Я не бачу, де у вашому проекті використовується стрімкий перелік в Об'єктиві 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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.