从匹配类型的字符串中获取 Swift 枚举类型,而不是 rawValue

Posted

技术标签:

【中文标题】从匹配类型的字符串中获取 Swift 枚举类型,而不是 rawValue【英文标题】:Get Swift enum type from string that matches type, not rawValue 【发布时间】:2020-11-12 12:13:32 【问题描述】:

我正在使用一个第三方库,该库有一个定义了一些媒体设备类型的枚举类。我还有一个 API,可以将媒体设备类型作为字符串提供给 Swift 代码。我需要以某种方式从该字符串中获取媒体设备类型 ,以便我可以将其传递给另一个方法。

第三方枚举

@objc public enum MediaDeviceType: Int, CustomStringConvertible 
    case audioBluetooth
    case audioWiredHeadset
    case audioBuiltInSpeaker
    case audioHandset
    case videoFrontCamera
    case videoBackCamera
    case other

    public var description: String 
        switch self 
        case .audioBluetooth:
            return "audioBluetooth"
        case .audioWiredHeadset:
            return "audioWiredHeadset"
        case .audioBuiltInSpeaker:
            return "audioBuiltInSpeaker"
        case .audioHandset:
            return "audioHandset"
        case .videoFrontCamera:
            return "videoFrontCamera"
        case .videoBackCamera:
            return "videoBackCamera"
        case .other:
            return "other"
        
    

我尝试过的事情:

如您所见,.rawValueInt,这意味着我无法使用枚举的初始化程序访问该值:

let stringType = "audioBluetooth"
let type = MediaDeviceType(rawValue: stringType)

这给了我错误:

无法将“String”类型的值转换为预期的参数类型“Int”

我想也许我可以 switch stringType 并返回正确的媒体设备类型,但它似乎在传递到下一个方法时实际上并没有按预期工作。

private func getMediaTypeStringToEnum(type: String) -> MediaDeviceType? 
    switch (type) 
    case "audioBluetooth":
      return .audioBluetooth
    case "audioWiredHeadset":
      return .audioWiredHeadset
    case "audioBuiltInSpeaker":
      return .audioBuiltInSpeaker
    case "audioHandset":
      return .audioHandset
    case "videoFrontCamera":
      return .videoFrontCamera
    case "videoBackCamera":
      return .videoBackCamera
    case "other":
      return .other
    default:
      return nil
    
  

下一个方法有两个参数,一个String,和一个可选的MediaDeviceType。如果第二个参数不匹配,则该方法切换init 方法。 Documentation.

我的基本实现:

let stringType = "audioBluetooth"
let label = "Media Device Label"
let hopefullyEnumType = getMediaTypeStringToEnum(stringType)
let mediaDevice = MediaDevice(label, hopefullyEnumType)

我是非常 Swift 新手,所以也许我在这里缺少一些明显的东西?

【问题讨论】:

“当传递给下一个方法时它实际上并没有按预期工作”是什么意思?你能提供一个minimal reproducible example吗? 你真的在使用 Swift3 吗?如果是这样,为什么? Swift 5.3 是最新版本。 @DávidPásztor 抱歉,我一定是不小心点击了那个 @Sweeper 添加了我的基本实现 hopefullyEnumType 是可选的。您需要先解包,然后才能将其传递给init,这需要一个非可选参数。 【参考方案1】:

如果您绝对确定枚举案例将来不会被新案例扩展,那么一种解决方案是遍历所有案例并查看哪些匹配:

private func getMediaTypeStringToEnum(type: String) -> MediaDeviceType? 
    let allMediaTypes: [MediaDeviceType] = [.audioBluetooth, .audioWiredHeadset, .audioBuiltInSpeaker, .audioHandset, .videoFrontCamera, .videoBackCamera, .other]
    return allMediaTypes.first  $0.description == type 

如果您不确定,则必须密切注意枚举声明,并在发生这种情况时将新案例添加到 allMediaTypes 数组中。

当然,如果枚举是 CaseIterable,那么您的问题将不太容易解决,并且不需要维护代码:

private func getMediaTypeStringToEnum(type: String) -> MediaDeviceType? 
    MediaDeviceType.allCases.first  $0.description == type 

作为旁注,您还可以在枚举上实现一个可失败的初始化程序,这应该使解决方案更易于使用,并且与枚举更具凝聚力:

extension MediaDeviceType 
    init?(string: String) 
        // do your thing
    

【讨论】:

这实际上与我最终做的事情非常相似,谢谢!问题实际上与枚举无关,而是与将特定 MediaDevice 存储在内存中的第三方 SDK 有关,但这没有记录在案。创建新的 MediaDevice 无效。令人沮丧,打算在他们的 GitHub 上发布一个关于它的问题。【参考方案2】:

快速代码是:

@objc public enum MediaDeviceType: Int, CustomStringConvertible 
case audioBluetooth
case audioWiredHeadset
case audioBuiltInSpeaker
case audioHandset
case videoFrontCamera
case videoBackCamera
case other

init(from string: String) 
    switch (string) 
        case "audioBluetooth":
            self = .audioBluetooth
        case "audioWiredHeadset":
            self = .audioWiredHeadset
        case "audioBuiltInSpeaker":
            self = .audioBuiltInSpeaker
        case "audioHandset":
            self = .audioHandset
        case "videoFrontCamera":
            self = .videoFrontCamera
        case "videoBackCamera":
            self = .videoBackCamera
        default:
            self = .other
        


public var description: String 
    switch self 
    case .audioBluetooth:
        return "audioBluetooth"
    case .audioWiredHeadset:
        return "audioWiredHeadset"
    case .audioBuiltInSpeaker:
        return "audioBuiltInSpeaker"
    case .audioHandset:
        return "audioHandset"
    case .videoFrontCamera:
        return "videoFrontCamera"
    case .videoBackCamera:
        return "videoBackCamera"
    case .other:
        return "other"
    


【讨论】:

很遗憾我无法更新第三方 SDK 代码

以上是关于从匹配类型的字符串中获取 Swift 枚举类型,而不是 rawValue的主要内容,如果未能解决你的问题,请参考以下文章

swift Swift中分隔符之前的子字符串(对于具有关联类型的枚举有用)

Swift学习笔记之---字符类型

Swift学习笔记之---字符类型

Swift 学习- 09 -- 枚举

Swift学习笔记:枚举

Swift-2.8枚举