Có thể sử dụng Enum của Swift trong Obj-C không?


144

Tôi đang cố gắng chuyển đổi một số lớp Obj-C của mình sang Swift. Và một số lớp Obj-C khác vẫn sử dụng enum trong lớp được chuyển đổi đó. Tôi đã tìm kiếm trong Tài liệu phát hành trước và không thể tìm thấy nó hoặc có thể tôi đã bỏ lỡ nó. Có cách nào để sử dụng Swift enum trong Lớp Obj-C không? Hoặc một liên kết đến tài liệu của vấn đề này?

Đây là cách tôi khai báo enum của mình trong mã Obj-C cũ và mã Swift mới.

Mã Obj-C cũ của tôi:

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

@interface SomeClass : NSObject

...

@end

Mã Swift mới của tôi:

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

class SomeClass: NSObject
{
    ...
}

Cập nhật: Từ các câu trả lời. Nó không thể được thực hiện trong Swift phiên bản cũ hơn 1.2. Nhưng theo Blog Swift chính thức này . Trong Swift 1.2 được phát hành cùng với XCode 6.3, Bạn có thể sử dụng Swift Enum trong Objective-C bằng cách thêm @objcvào trướcenum


Thực sự không cần phải thay đổi mã hiện tại của bạn. Để tương tác giữa Swift và Objective-C, hãy xem video WWDC.
gnasher729

Tôi chỉ muốn kiểm tra xem dự án của tôi có còn hoạt động không nếu có một lớp nhanh chóng trong dự án của tôi trong tương lai nhưng tôi không thể tìm ra lớp nào tôi nên thêm để kiểm tra nó. Vì vậy, tôi chuyển đổi cái cũ thay thế. Dù sao, cảm ơn sự giúp đỡ của bạn.
myLifeasdog

Câu trả lời:


226

Kể từ phiên bản Swift 1.2 (Xcode 6.3), bạn có thể. Đơn giản chỉ cần tiền tố khai báo enum với@objc

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

Không biết xấu hổ lấy từ Blog Swift

Lưu ý: Điều này sẽ không hoạt động đối với các chuỗi enum hoặc enum với các giá trị liên quan. Enum của bạn sẽ cần phải được ràng buộc


Trong Objective-C, nó sẽ trông giống như

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

8
cảm ơn rất nhiều vì đã chỉ ra ... lưu ý rằng trong object-c mặc dù các giá trị enum sẽ được gọi BearBlack, BearGrizzlyBearPolar!
nburk

1
Điều đó có ý nghĩa không? Đặc biệt là khi bạn nhìn vào cách nó được dịch từ obj-c sang swift .. @nburk
Daniel Galasko

1
Vâng, điều này hoạt động. Tuy nhiên, ít nhất trong trường hợp của tôi, một thuộc tính "công khai" phải được thêm vào bảng liệt kê để nó có thể truy cập được ở phía Objective-C của dự án, như sau: "@objc public enum Bear: Int"
Pirkka Esko

Quá tệ Tôi không thấy bất kỳ bằng chứng nào cho thấy giá trị liên quan đến Swift enum là có thể. suy nghĩ mơ ước
finneycanhelp

2
@AJit tại sao bạn muốn làm điều đó? Chỉ cần thêm enum vào tiêu đề của riêng nó và nhập vào tiêu đề bắc cầu nếu không nó là độc quyền của Swift
Daniel Galasko

31

Để mở rộng câu trả lời đã chọn ...

Có thể chia sẻ enum kiểu Swift giữa Swift và Objective-C bằng cách sử dụng NS_ENUM().

Chúng chỉ cần được xác định trong bối cảnh Objective-C bằng cách sử dụng NS_ENUM()và chúng được cung cấp bằng cách sử dụng ký hiệu dấu chấm Swift.

Từ việc sử dụng Swift với ca cao và khách quan-C

Swift nhập dưới dạng liệt kê Swift bất kỳ phép liệt kê kiểu C nào được đánh dấu bằng NS_ENUMmacro. Điều này có nghĩa là các tiền tố cho tên giá trị liệt kê được cắt bớt khi chúng được nhập vào Swift, cho dù chúng được xác định trong khung hệ thống hoặc trong mã tùy chỉnh.

Mục tiêu-C

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

Nhanh

let cellStyle: UITableViewCellStyle = .Default

Tôi nhận được tại UITableViewCellStyle "định nghĩa hàm không được phép ở đây", tôi đang làm gì sai? Tất nhiên tôi có tên khác nhau không phải UITableViewCellStyle.
Cristi Băluță

1
Như đã lưu ý trong câu trả lời của ông Galasko bên dưới, Swift 1.2 cho phép các enum được định nghĩa trong Swift và có sẵn trong Obj-c. Kiểu định nghĩa này, cụ thể là NS_ENUM, vẫn hoạt động trong Obj-c, nhưng kể từ phiên bản Swift 1.2, bạn có thể sử dụng một trong hai tùy chọn.
SirNod

Tôi thấy có một vấn đề với enj ObjC trong Swift: Chúng không khả dụng. Trong một đoạn như if let a = MyEnum(rawValue: 12345)12345 không phải là một phần của enum đó, kết quả không phải là một tùy chọn mà là một số enum không hợp lệ.
sinh học

30

Từ hướng dẫn Sử dụng Swift với Ca cao và Mục tiêu-C :

Một lớp hoặc giao thức Swift phải được đánh dấu bằng thuộc tính @objc để có thể truy cập và sử dụng được trong Objective-C. [...]

Bạn sẽ có quyền truy cập vào bất cứ thứ gì trong một lớp hoặc giao thức được đánh dấu bằng thuộc tính @objc miễn là nó tương thích với Objective-C. Điều này không bao gồm các tính năng chỉ dành cho Swift, chẳng hạn như các tính năng được liệt kê ở đây:

Generics Tuples / Enumerations được xác định trong Swift / Structures được xác định trong Swift / Top-level function được xác định trong Swift / Global biến được xác định trong Swift / typealiases được xác định trong Swift / Swift-style-type

Vì vậy, không, bạn không thể sử dụng một enum Swift trong lớp Objective-C.


2
Có một cách giải quyết? Ý tôi là nếu tôi tạo một lớp Swift và tôi hoàn toàn cần một enum. Làm thế nào tôi có thể biến enum đó thành có thể sử dụng được trong Objective-C?
Raul Lopez

4
@RaulLopezVillalpando Nếu bạn biết bạn sẽ tương tác với Objective-C, thì bạn nên khai báo phép liệt kê trong Objective-C và để cả hai ngôn ngữ chia sẻ nó.
Gregory Higley

3
"Vâng, vì vậy chúng tôi đã tạo ra cây cầu này để giúp bạn chuyển sang Swift, nhưng thật vô ích nếu bạn muốn sử dụng bất cứ thứ gì hay ho, như Enums, Structs, Generics ... Vì vậy, đó là ..."
Kevin R

22
CÂU TRẢ LỜI NÀY KHÔNG CÓ GIÁ TRỊ DÀI HƠN !! kể từ Xcode 6.3 / Swift 1.2, các @objcenum Swift cũng có thể được sử dụng trong mục tiêu-c bằng cách sử dụng như @DanielGalasko đã chỉ ra trong câu trả lời của mình bên dưới !!!
nburk

9
Chỉ cần làm rõ nhận xét trên, trích dẫn văn bản hiện tại trên tài liệu kể từ Swift 2.1 , "Số liệt kê được xác định trong Swift không có loại giá trị thô Int ". Vì vậy, nếu enum của bạn trong Swift được khai báo với loại giá trị thô Int như trong @obj enum MyEnum: Intnó sẽ hoạt động tốt trên các tệp Objective-C như đã đề cập trước đó. Nếu enum của bạn được khai báo với một loại giá trị thô khác như @obj enum MyOtherEnum: String, bạn sẽ không thể sử dụng nó trên các tệp Objective-C
jjramos 17/03/2016

7

Swift 4.1, Xcode 9.4.1:

1) Swift enum phải được thêm tiền tố @objcvà là Intloại:

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

2) Tên Objective-C là tên enum + tên trường hợp, vd 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;
    }
}

Và, tất nhiên, hãy nhớ nhập tiêu đề bắc cầu Swift của bạn làm mục cuối cùng trong danh sách nhập tệp của Objective-C:

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

Tại sao MyApp-Swift phải là người cuối cùng?
Paul T.

@PaulT. : có lẽ phải làm theo thứ tự xử lý. Hãy thử đặt nó ở nơi khác và bạn sẽ thấy nó không hoạt động.
leanne

Tôi đã kiểm tra, trong dự án hiện tại của tôi gần như trong tất cả các tệp, nó ở cuối phần nhập, nhưng trong một số tệp thì nó không ở cuối và dự án hoạt động. có thể trong một Xcode mới nó hoạt động? Tôi không thể kiểm tra ngay bây giờ, vì dự án hiện tại của tôi mất nhiều thời gian để biên dịch :), nhưng tôi sẽ kiểm tra nó sau
Paul T.

2

Nếu bạn muốn giữ mã ObjC như hiện tại, bạn có thể thêm tệp tiêu đề của trình trợ giúp trong dự án của mình:

Swift2Objc_Helper.h

trong tệp tiêu đề thêm loại enum này:

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

Có thể có một vị trí khác trong tệp .m của bạn để thực hiện thay đổi: bao gồm tệp tiêu đề ẩn:

#import "[YourProjectName]-Swift.h"

thay thế [YourProjectName] bằng tên dự án của bạn. Tệp tiêu đề này hiển thị tất cả các lớp @objc do Swift định nghĩa, enum cho ObjC.

Bạn có thể nhận được một thông báo cảnh báo về chuyển đổi ngầm định từ loại liệt kê ... Không sao cả.

Nhân tiện, bạn có thể sử dụng tệp trình trợ giúp tiêu đề này để giữ một số mã ObjC như #define hằng.


0

Nếu bạn (như tôi) thực sự muốn sử dụng các enum String, bạn có thể tạo một giao diện chuyên dụng cho object-c. Ví dụ:

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

Tất nhiên, điều này sẽ không cung cấp cho bạn sự tiện lợi của tự động hoàn thành (trừ khi bạn xác định các hằng số bổ sung trong môi trường object-c).


0

điều này có thể giúp nhiều hơn một chút

Báo cáo vấn đề : - Tôi có enum trong lớp swift, mà tôi đang truy cập từ các lớp swift khác, và bây giờ tôi cần truy cập nó tạo thành một trong những lớp C mục tiêu.

Trước khi truy cập nó từ lớp object-c: -

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

Thay đổi để truy cập nó từ lớp c khách quan

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

và thêm một hàm để truyền nó vào giá trị

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

0

Sau khi nghiên cứu điều này, tôi tiếp tục chỉ tìm thấy một phần câu trả lời, vì vậy tôi đã tạo ra toàn bộ ví dụ về Ứng dụng Swift được kết nối với Objective C có các enum Swift được sử dụng bởi mã Objective C và enive C của Objective C được sử dụng bởi mã Swift. Đây là một dự án Xcode đơn giản mà bạn có thể chạy và thử nghiệm. Nó được viết bằng Xcode 10.3 với Swift 5.0

Dự án ví dụ


Tôi không thấy, nơi dự án của bạn sử dụng enum nhanh chóng trong Mục tiêu C. Ngoài ra định nghĩa về enum nhanh chóng enum SwAnimalthiếu hàng đầu@obj
oliolioli

0

Trong trường hợp bạn đang cố gắng quan sát một enum trông như thế này:

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

cách giải quyết này đã giúp tôi.

Lớp quan sát:

  • tạo nên @objc dynamic var observable: String?
  • tạo ví dụ enum của bạn như thế này:

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

Lớp quan sát viên:

  • tạo nên private var _enumName: EnumName?
  • tạo nên private let _instance = ObservableClass()
  • tạo nên

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

Hơn nó Bây giờ mỗi khi bạn thay đổi _enumNametrong lớp có thể quan sát, một thể hiện thích hợp trên lớp người quan sát cũng sẽ được cập nhật ngay lập tức.

Tất nhiên đây là một triển khai đơn giản hóa, nhưng nó sẽ cho bạn ý tưởng về cách quan sát các thuộc tính không tương thích KVO.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.