Чи можливо використовувати 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.