Obj-CでSwiftのEnumを使用することは可能ですか?


144

Obj-Cクラスの一部をSwiftに変換しようとしています。そして、他のいくつかのObj-Cクラスは、その変換されたクラスでまだ列挙型を使用しています。プレリリースドキュメントで検索しましたが、見つからなかったか、見逃してしまいました。Obj-CクラスでSwift enumを使用する方法はありますか?または、この問題のドキュメントへのリンク?

これは、古い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
{
    ...
}

更新:回答から。1.2より古いバージョンのSwiftではできません。しかし、この公式のSwift Blogによると。スウィフト1.2でXCodeの6.3とともにリリースされていること、あなたは追加することにより、Objective-Cでスウィフト列挙型を使用することができます@objcの前にenum


実際に既存のコードを変更する必要はありません。SwiftとObjective-Cの相互作用については、WWDCビデオをご覧ください。
gnasher729 2014年

将来プロジェクトに迅速なクラスが存在する場合、プロジェクトがまだ機能するかどうかを確認したいだけですが、テストするためにどのクラスを追加すればよいのかわかりません。そこで、代わりに古いものを変換します。とにかく、あなたの助けに感謝します。
myLifeasdog 2014年

回答:


226

Swiftバージョン1.2(Xcode 6.3)以降で可能です。enum宣言の前に単に@objc

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

恥知らずにSwiftブログから取得

注:これは、文字列の列挙型または関連付けられた値を持つ列挙型では機能しません。列挙型はInt-boundである必要があります


Objective-Cでは、次のようになります。

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

8
たくさんのことを指摘...ノートをObjective-Cで列挙値が呼び出しになりますけれどもていることに感謝しBearBlackBearGrizzlyそしてBearPolar
nburk

1
それは意味がありませんか?特に、obj-cからswiftへの変換方法を見ると、@ nburk
Daniel Galasko

1
はい、これでうまくいきます。ただし、少なくとも私の場合、 "@ objc public enum Bear:Int"
Pirkka Esko

残念ながら、Swift enumに関連する値が可能であるという証拠はありません。希望的思考
finneycanhelp 2015

2
@AJitどうしてそんなことしたいの?enumを独自のヘッダーに追加して、それをブリッジングヘッダーにインポートするだけです。それ以外の場合は、Swiftに限定されます
Daniel Galasko

31

選択した回答を拡張するには...

を使用して、Swiftスタイルの列挙型をSwiftとObjective-Cの間で共有することができNS_ENUM()ます。

これらはObjective-Cコンテキストで定義する必要があるだけで、NS_ENUM()Swiftドット表記を使用して利用できます。

CocoaおよびObjective-CでのSwift使用から

Swiftは、NS_ENUMマクロでマークされたCスタイルの列挙をSwift列挙としてインポートします。つまり、列挙値の名前のプレフィックスは、システムフレームワークで定義されているか、カスタムコードで定義されているかに関係なく、Swiftにインポートされるときに切り捨てられます。

Objective-C

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

迅速

let cellStyle: UITableViewCellStyle = .Default

UITableViewCellStyleで「関数定義はここでは許可されていません」と表示されますが、何が問題ですか?もちろん、UITableViewCellStyleではなく、別の名前を付けています。
Cristi Băluță 2014年

1
下記のGalasko氏の回答で述べたように、Swift 1.2では列挙型をSwiftで定義してObj-cで使用できるようになっています。この定義のスタイル、つまりNS_ENUMはObj-cでも機能しますが、Swiftバージョン1.2以降では、どちらのオプションも使用できます。
サーノッド2015年

私はSwiftのObjC列挙型に問題があることを発見しました:失敗することはありません。if let a = MyEnum(rawValue: 12345)12345がその列挙型の一部ではないようなフラグメントでは、結果はオプションではなく、いくつかの無効な列挙型です。
バイオ

30

CocoaおよびObjective-CでのSwift使用ガイドから:

Objective-Cでアクセスおよび使用できるようにするには、Swiftクラスまたはプロトコルを@objc属性でマークする必要があります。[...]

Objective-Cと互換性がある限り、@ objc属性でマークされたクラスまたはプロトコル内のすべてにアクセスできます。これは、以下にリストされているようなSwiftのみの機能を除外します。

ジェネリックタプル/ Swiftで定義された列挙型 / Swiftで定義された構造体/ Swiftで定義されたトップレベル関数/ Swiftで定義されたグローバル変数/ Swiftで定義されたタイプエイリアス/ Swiftスタイルのバリアード/ネストされた型/カリー化された関数

したがって、いいえ、Objective-CクラスでSwift列挙型を使用することはできません。


2
回避策はありますか?つまり、Swiftクラスを作成し、列挙型が絶対に必要な場合です。その列挙型をObjective-Cでも使用できるようにするにはどうすればよいですか?
Raul Lopez

4
@RaulLopezVillalpando Objective-Cと相互運用する予定がある場合は、Objective-Cで列挙型を宣言し、両方の言語で共有できるようにする必要があります。
Gregory Higley 2014年

3
「そうですね、Swiftへの移行を支援するためにこのブリッジを作成しましたが、Enums、Structs、Genericsなどのクールなものを使用したくても役に立たないので...」
Kevin R

22
この回答は有効ではありません!! Xcode 6.3 / Swift 1.2以降@objc、@ DanielGalaskoが彼の回答で指摘したように、Swift列挙型をObjective-C内でも使用できます!!!
nburk

9
上記のコメントを明確にするために、Swift 2.1の時点でドキュメントの現在のテキストを引用して、「Int raw値タイプなしで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)Swift enumの前@objcIntタイプを付ける必要があります:

// 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ブリッジヘッダーをObjective-Cファイルのインポートリストの最後の項目としてインポートすることを忘れないでください。

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

MyApp-Swiftを最後にする必要があるのはなぜですか?
ポールT.

@PaulT。:おそらく処理の順序と関係があります。別の場所に置いてみてください。そうしないと機能しません。
リーン

私がチェックしたところ、現在のプロジェクトではほとんどすべてのファイルでインポートセクションの最後にありますが、いくつかのファイルでは最後ではなく、プロジェクトは機能します。それが動作する新しいXcodeにあるかもしれませんか?現在のプロジェクトのコンパイルには時間がかかるため、今は確認できませんが、後で確認します
Paul T.

2

ObjCコードをそのままにしたい場合は、プロジェクトにヘルパーヘッダーファイルを追加できます。

Swift2Objc_Helper.h

ヘッダーファイルに次の列挙型を追加します。

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

.mファイルに変更を加える別の場所があるかもしれません:非表示のヘッダーファイルを含めるには:

#import "[YourProjectName]-Swift.h"

[YourProjectName]をプロジェクト名に置き換えます。このヘッダーファイルは、Swiftで定義されたすべての@objcクラス、列挙型をObjCに公開します。

列挙型からの暗黙の変換に関する警告メッセージが表示される場合があります...それは問題ありません。

ちなみに、このヘッダーヘルパーファイルを使用すると、#define定数などの一部のObjCコードを保持できます。


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

これはもう少し役立つかもしれません

問題の説明:-私は他のSwiftクラスからアクセスしているSwiftクラスに列挙型があり、目的のCクラスの1つからアクセスする必要があります。

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

これを調査した後、私は部分的な答えのみを見つけ続けたので、Objective Cコードに使用されるSwift列挙型とSwiftコードで使用されるObjective C列挙型を持つObjective CにブリッジされるSwiftアプリの完全な例を作成しました。これは、実行して実験できる単純なXcodeプロジェクトです。それはSwift 5.0でXcode 10.3を使用して書かれました

プロジェクト例


わかりません。プロジェクトでObjective Cのenum SwAnimal@obj
Swift

0

次のような列挙型を観察しようとしている場合:

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

この回避策は私を助けました。

観察可能なクラス:

  • つくる @objc dynamic var observable: String?
  • 次のようにenumインスタンスを作成します。

    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で、observableクラスでを変更するたびに、observerクラスの適切なインスタンスも即座に更新されます。

もちろん、これは単純化された実装ですが、KVOと互換性のないプロパティを監視する方法についてのアイデアが得られるはずです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.