How to make a Swift String enum available in Objective-C?

前端 未结 10 2105
情深已故
情深已故 2020-12-01 07:09

I have this enum with String values, which will be used to tell an API method that logs to a server what kind of serverity a message has. I\'m using Swift 1.2,

相关标签:
10条回答
  • 2020-12-01 07:29

    Code for Xcode 8, using the fact that Int works but other methods aren't exposed to Objective-C. This is pretty horrible as it stands...

    class EnumSupport : NSObject {
        class func textFor(logSeverity severity: LogSeverity) -> String {
            return severity.text()
        }
    }
    
    @objc public enum LogSeverity: Int {
        case Debug
        case Info
        case Warn
        case Error
    
        func text() -> String {
            switch self {
                case .Debug: return "debug"
                case .Info: return "info"
                case .Warn: return "warn"
                case .Error: return "error"
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-01 07:30

    I think @Remi 's answer crashes in some situations as I had this:

    My error's screesshot. so I post my edition for @Remi 's answer:

    @objc public enum LogSeverity: Int, RawRepresentable {
        case debug
        case info
        case warn
        case error
    
        public typealias RawValue = String
    
        public var rawValue: RawValue {
            switch self {
                case .debug:
                    return "DEBUG"
                case .info:
                    return "INFO"
                case .warn:
                    return "WARN"
                case .error:
                    return "ERROR"
            }
        }
    
        public init?(rawValue: RawValue) {
            switch rawValue {
                case "DEBUG":
                    self = .debug
                case "INFO":
                    self = .info
                case "WARN":
                    self = .warn
                case "ERROR":
                    self = .error
                default:
                    return nil
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-01 07:35

    Here's a solution that works.

    @objc public enum ConnectivityStatus: Int {
        case Wifi
        case Mobile
        case Ethernet
        case Off
    
        func name() -> String {
            switch self {
            case .Wifi: return "wifi"
            case .Mobile: return "mobile"
            case .Ethernet: return "ethernet"
            case .Off: return "off"
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-01 07:37

    This is my use case:

    • I avoid hard-coded Strings whenever I can, so that I get compile warnings when I change something
    • I have a fixed list of String values coming from a back end, which can also be nil

    Here's my solution that involves no hard-coded Strings at all, supports missing values, and can be used elegantly in both Swift and Obj-C:

    @objc enum InventoryItemType: Int {
        private enum StringInventoryItemType: String {
            case vial
            case syringe
            case crystalloid
            case bloodProduct
            case supplies
        }
    
        case vial
        case syringe
        case crystalloid
        case bloodProduct
        case supplies
        case unknown
    
        static func fromString(_ string: String?) -> InventoryItemType {
            guard let string = string else {
                return .unknown
            }
            guard let stringType = StringInventoryItemType(rawValue: string) else {
                return .unknown
            }
            switch stringType {
            case .vial:
                return .vial
            case .syringe:
                return .syringe
            case .crystalloid:
                return .crystalloid
            case .bloodProduct:
                return .bloodProduct
            case .supplies:
                return .supplies
            }
        }
    
        var stringValue: String? {
            switch self {
            case .vial:
                return StringInventoryItemType.vial.rawValue
            case .syringe:
                return StringInventoryItemType.syringe.rawValue
            case .crystalloid:
                return StringInventoryItemType.crystalloid.rawValue
            case .bloodProduct:
                return StringInventoryItemType.bloodProduct.rawValue
            case .supplies:
                return StringInventoryItemType.supplies.rawValue
            case .unknown:
                return nil
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-01 07:37

    Here's what I came up with. In my case, this enum was in the context providing info for a specific class, ServiceProvider.

    class ServiceProvider {
        @objc enum FieldName : Int {
            case CITY
            case LATITUDE
            case LONGITUDE
            case NAME
            case GRADE
            case POSTAL_CODE
            case STATE
            case REVIEW_COUNT
            case COORDINATES
    
            var string: String {
                return ServiceProvider.FieldNameToString(self)
            }
        }
    
        class func FieldNameToString(fieldName:FieldName) -> String {
            switch fieldName {
            case .CITY:         return "city"
            case .LATITUDE:     return "latitude"
            case .LONGITUDE:    return "longitude"
            case .NAME:         return "name"
            case .GRADE:        return "overallGrade"
            case .POSTAL_CODE:  return "postalCode"
            case .STATE:        return "state"
            case .REVIEW_COUNT: return "reviewCount"
            case .COORDINATES:  return "coordinates"
            }
        }
    }
    

    From Swift, you can use .string on an enum (similar to .rawValue). From Objective-C, you can use [ServiceProvider FieldNameToString:enumValue];

    0 讨论(0)
  • 2020-12-01 07:37

    You can create an private Inner enum. The implementation is a bit repeatable, but clear and easy. 1 line rawValue, 2 lines init, which always look the same. The Inner has a method returning the "outer" equivalent, and vice-versa.

    Has the added benefit that you can directly map the enum case to a String, unlike other answers here.

    Please feel welcome to build on this answer if you know how to solve the repeatability problem with templates, I don't have time to mingle with it right now.

    @objc enum MyEnum: NSInteger, RawRepresentable, Equatable {
        case
        option1,
        option2,
        option3
    
        // MARK: RawRepresentable
    
        var rawValue: String {
            return toInner().rawValue
        }
    
        init?(rawValue: String) {
            guard let value = Inner(rawValue: rawValue)?.toOuter() else { return nil }
            self = value
        }
    
        // MARK: Obj-C support
    
        private func toInner() -> Inner {
            switch self {
            case .option1: return .option1
            case .option3: return .option3
            case .option2: return .option2
            }
        }
    
        private enum Inner: String {
            case
            option1 = "option_1",
            option2 = "option_2",
            option3 = "option_3"
    
            func toOuter() -> MyEnum {
                switch self {
                case .option1: return .option1
                case .option3: return .option3
                case .option2: return .option2
                }
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题