เป็นไปได้หรือไม่ที่จะใช้ Swift's Enum ใน Obj-C


145

ฉันพยายามแปลงคลาส Obj-C ของฉันเป็น Swift และคลาส Obj-C อื่น ๆ ยังคงใช้ enum ในคลาสที่แปลงแล้ว ฉันค้นหาในเอกสารเผยแพร่ล่วงหน้าและไม่พบหรืออาจพลาด มีวิธีใช้ Swift enum ใน Obj-C Class หรือไม่? หรือลิงค์ไปยังเอกสารของปัญหานี้หรือไม่?

นี่คือวิธีที่ฉันประกาศ enum ของฉันในรหัส Obj-C เก่าและรหัส Swift ใหม่

รหัส Obj-C เก่าของฉัน:

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

@interface SomeClass : NSObject

...

@end

Swift Code ใหม่ของฉัน:

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) คุณสามารถ เพียงนำหน้าการประกาศ enum ด้วย@objc

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

นำมาจากบล็อกอย่างรวดเร็ว

หมายเหตุ: สิ่งนี้จะไม่ทำงานสำหรับ String enums หรือ enums ด้วยค่าที่เกี่ยวข้อง Enum ของคุณจะต้องมีขอบเขต


ใน Objective-C จะมีลักษณะเช่นนี้

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

8
ขอบคุณมากสำหรับการชี้ออก ... ทราบว่าในวัตถุประสงค์ -c แม้ว่าค่า enum จะโทรBearBlack, BearGrizzlyและBearPolar!
nburk

1
นั่นทำให้รู้สึกไม่? โดยเฉพาะอย่างยิ่งเมื่อคุณดูว่ามันแปลจาก obj-c เป็น swift .. @nburk
Daniel Galasko

1
ใช่มันใช้งานได้ อย่างไรก็ตามอย่างน้อยในกรณีของฉันต้องเพิ่มแอตทริบิวต์ "สาธารณะ" ลงในการแจงนับเพื่อให้สามารถเข้าถึงได้ในด้านวัตถุประสงค์ -C ของโครงการเช่นนี้: "@objc public enum Bear: Int"
Pirkka Esko

น่าเสียดายที่ฉันไม่เห็นหลักฐานใด ๆ ที่เป็นไปได้ของค่าที่เกี่ยวข้องของ Swift enum คิดอย่างปรารถนา
finneycanhelp

2
@Ait ทำไมคุณต้องการทำเช่นนั้น? เพียงเพิ่ม enum ในส่วนหัวของตัวเองและนำเข้าที่ในส่วนหัว bridging มิฉะนั้นมันจะเป็นเอกสิทธิ์ของ Swift
Daniel Galasko

31

หากต้องการขยายคำตอบที่เลือก ...

มันเป็นไปได้ที่จะแบ่งปัน enums สไตล์สวิฟท์ระหว่างสวิฟท์และวัตถุประสงค์ -C NS_ENUM()ใช้

พวกเขาเพียงแค่ต้องกำหนดในบริบทการใช้ Objective-C NS_ENUM()และพวกเขาจะให้บริการโดยใช้สัญกรณ์จุด Swift

จากการใช้ Swift กับ Cocoa และ Objective-C

Swift นำเข้าเป็น Swift การแจงนับ C สไตล์ใด ๆ ที่มีเครื่องหมายNS_ENUMแมโคร ซึ่งหมายความว่าคำนำหน้าชื่อการแจงนับจะถูกปัดเศษเมื่อนำเข้าสู่ Swift ไม่ว่าจะถูกกำหนดไว้ในกรอบงานระบบหรือในรหัสที่กำหนดเอง

Objective-C

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

รวดเร็ว

let cellStyle: UITableViewCellStyle = .Default

ฉันได้รับที่ UITableViewCellStyle "คำจำกัดความฟังก์ชันไม่ได้รับอนุญาตที่นี่" ฉันทำอะไรผิด แน่นอนฉันมีชื่อต่างกันไม่ใช่ UITableViewCellStyle
Cristi Băluță

1
ดังที่ระบุไว้ในคำตอบของ Mr. Galasko ด้านล่าง Swift 1.2 อนุญาตให้กำหนด enums ใน Swift และ Obj-c คำจำกัดความลักษณะนี้คือ NS_ENUM ยังคงทำงานใน Obj-c แต่ใน Swift เวอร์ชัน 1.2 คุณสามารถใช้ตัวเลือกใดตัวเลือกหนึ่งได้
SirNod

ฉันพบว่ามีปัญหากับ ObjC enums ใน Swift: พวกเขาไม่พร้อมใช้งาน ในส่วนif let a = MyEnum(rawValue: 12345)ที่ 12345 ไม่ได้เป็นส่วนหนึ่งของ enum ผลลัพธ์ไม่ได้เป็นตัวเลือก แต่มีบาง enum ที่ไม่ถูกต้อง
bio

30

จากคู่มือการใช้งาน Swift with Cocoa และ Objective-C :

คลาสหรือโปรโตคอล Swift จะต้องทำเครื่องหมายด้วยแอตทริบิวต์ @objc เพื่อให้สามารถเข้าถึงและใช้งานได้ใน Objective-C [ ... ]

คุณจะสามารถเข้าถึงสิ่งต่าง ๆ ภายในคลาสหรือโพรโทคอลที่มีเครื่องหมาย @objc ได้ตราบใดที่มันเข้ากันได้กับ Objective-C สิ่งนี้ไม่รวมคุณสมบัติ Swift-only เช่นที่อยู่ในรายการ:

Generic Tuples / Enumerations ที่กำหนดใน Swift / โครงสร้างที่กำหนดไว้ในฟังก์ชัน Swift / Top-level ที่กำหนดไว้ในตัวแปร Swift / Global กำหนดไว้ใน Swift / Typealiases ที่กำหนดใน Swadad / Swift-style Variadics / ฟังก์ชัน Nested Type / Curried

ดังนั้นไม่คุณไม่สามารถใช้ Swift enum ในคลาส Objective-C


2
มีวิธีแก้ปัญหาหรือไม่? ฉันหมายถึงถ้าฉันสร้างคลาส Swift และฉันต้องการ enum อย่างแน่นอน ฉันจะทำให้ enum นั้นใช้งานได้ใน Objective-C ด้วยหรือไม่
Raul Lopez

4
@RaulLopezVillalpando หากคุณรู้ว่าคุณกำลังจะประสานงานกับ Objective-C คุณควรประกาศการแจงนับใน Objective-C และให้ทั้งสองภาษาแบ่งปัน
Gregory Higley

3
"ใช่แล้วเราสร้างสะพานนี้เพื่อช่วยให้คุณเปลี่ยนไปใช้ Swift แต่ก็ไร้ประโยชน์ถ้าคุณต้องการใช้อะไรที่เจ๋ง ๆ เช่น Enums, Structs, Generics ... มันมี ... "
Kevin R

22
คำตอบนี้ไม่ถูกต้องอีกต่อไป !! ตั้งแต่ Xcode 6.3 / Swift 1.2 Swums enums ยังสามารถใช้ในวัตถุประสงค์ -c โดยใช้@objc@DanielGalasko ชี้ให้เห็นในคำตอบของเขาด้านล่าง !!!
nburk

9
เพียงเพื่อชี้แจงความคิดเห็นข้างต้นโดยอ้างข้อความปัจจุบันในเอกสารประกอบของ Swift 2.1 "การแจกแจงที่กำหนดใน Swift โดยไม่ต้องพิมพ์ค่าชนิด Int " ดังนั้นหาก enum ของคุณใน Swift ได้รับการประกาศด้วยค่า Int raw type ซึ่ง@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 จะต้องนำหน้าด้วย@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 ของคุณเป็นรายการสุดท้ายในรายการนำเข้าของไฟล์ Objective-C:

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

ทำไม MyApp-Swift ควรเป็นครั้งสุดท้าย
พอลต.

@PaulT : อาจเกี่ยวข้องกับลำดับการประมวลผล ลองวางที่อื่นแล้วคุณจะเห็นว่ามันใช้งานไม่ได้
ลีแอนน์

ฉันตรวจสอบในโครงการปัจจุบันของฉันเกือบทุกไฟล์มันอยู่ที่ส่วนท้ายของการนำเข้า แต่ในหลาย ๆ ไฟล์มันไม่ได้สิ้นสุดและโครงการทำงานได้ อาจอยู่ใน Xcode ใหม่มันใช้งานได้? ฉันไม่สามารถตรวจสอบได้ตอนนี้เพราะโครงการปัจจุบันของฉันใช้เวลาในการรวบรวมนาน :) แต่ฉันจะตรวจสอบในภายหลัง
Paul T.

2

หากคุณต้องการเก็บรหัส ObjC ตามที่เป็นอยู่คุณสามารถเพิ่มไฟล์ส่วนหัวผู้ช่วยในโครงการของคุณ:

Swift2Objc_Helper.h

ในไฟล์ส่วนหัวเพิ่ม enum ประเภทนี้:

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

อาจมีที่อื่นในไฟล์. m ของคุณเพื่อทำการเปลี่ยนแปลง: เพื่อรวมไฟล์ส่วนหัวที่ซ่อนอยู่:

#import "[YourProjectName]-Swift.h"

แทนที่ [YourProjectName] ด้วยชื่อโครงการของคุณ ไฟล์ส่วนหัวนี้เปิดเผยคลาส @objc ที่ Swift กำหนดไว้ทั้งหมดให้กับ ObjC

คุณอาจได้รับข้อความเตือนเกี่ยวกับการแปลงโดยนัยจากประเภทการแจงนับ ... มันก็โอเค

อย่างไรก็ตามคุณสามารถใช้ไฟล์ตัวช่วยส่วนหัวนี้เพื่อเก็บรหัส ObjC บางอย่างเช่น #define constants


0

หากคุณ (เช่นฉัน) ต้องการใช้ประโยชน์จาก String enums จริงๆคุณสามารถสร้างอินเทอร์เฟซพิเศษสำหรับวัตถุประสงค์ -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))
}

แน่นอนว่าสิ่งนี้จะไม่ให้ความสะดวกในการเติมข้อมูลอัตโนมัติ (เว้นแต่คุณจะกำหนดค่าคงที่เพิ่มเติมในสภาพแวดล้อมที่มีวัตถุประสงค์


0

นี่อาจช่วยได้มากกว่านี้

คำแถลงปัญหา : - ฉันมี enum ในคลาส swift ซึ่งฉันกำลังเข้าถึงคลาส swift อื่น ๆ และตอนนี้ฉันต้องการเข้าถึงมันในรูปแบบหนึ่งในคลาส C วัตถุประสงค์ของฉัน

ก่อนที่จะเข้าถึงได้จากคลาส 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 App ที่เชื่อมต่อกับ Objective C ที่มี Swift enums ที่ใช้โดยรหัส Objective C และ Objective C enums ที่ใช้โดย Swift code มันเป็นโครงการ Xcode ง่ายๆที่คุณสามารถเรียกใช้และทดลองใช้ มันเขียนโดยใช้ Xcode 10.3 พร้อม Swift 5.0

ตัวอย่างโครงการ


ฉันไม่เห็นว่าโครงการของคุณใช้ swift enum ใน Objective C หรือไม่คำจำกัดความของ swift enum ยังenum SwAnimalขาดผู้นำ@obj
oliolioli

0

ในกรณีที่คุณพยายามสังเกต enum ซึ่งมีลักษณะดังนี้:

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คลาสที่สังเกตได้อินสแตนซ์ที่เหมาะสมของคลาสผู้สังเกตการณ์จะได้รับการอัปเดตทันทีเช่นกัน

แน่นอนว่านี่เป็นการใช้งานที่เกินความจริง แต่ควรให้แนวคิดในการสังเกตคุณสมบัติที่เข้ากันไม่ได้ของ KVO

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.