如何减少Swift枚举转换代码

时间:2018-01-01 22:46:05

标签: swift generics core-data enums

我有各种各样的枚举,例如下面的内容。

enum PaperOrientation : Int { case portrait, landscape }
enum MetricType : Int { case inches, metric }

我创建了Int类型的枚举,以便可以使用CoreData将实例的值保存为数字。

从CoreData中检索要在程序中使用的值时,我最终会得到非常相似的转换例程,如下所示。

通常,我想要一些默认值 - 例如,对于最新版本的程序,它是新枚举的情况,并且该变量的值实际上可能实际上没有保存在CoreData中。例如,为程序的第二次转换添加了MetricType。检索在rev 1中创建的纸张将不会保存度量值。对于零值,我想使用最初假定纸张的默认值。

class ConversionRoutine {

    class func orientationFor(_ num: NSNumber?) -> PaperOrientation {
        if let iVal = num?.intValue {
            if let val = PaperOrientation(rawValue: iVal) {
                return val
            }
        }
        return PaperOrientation(rawValue: 0)!
    }

    class func metricTypeFor(_ num: NSNumber?) -> MetricType {
        if let iVal = num?.intValue {
            if let val = MetricType(rawValue: iVal) {
                return val
            }
        }
        return MetricType(rawValue: 0)!
    }
}

有没有办法减少冗余?

我提出了一个非常好的方法。但欢迎更多改进或改进。

2 个答案:

答案 0 :(得分:3)

下面的Swift 4示例使用基于RawRepresentable的Defaultable协议。第一步是创建一个defaultValue,可以在初始化程序失败时使用。请注意,Defaultable协议不限于Int枚举。 String枚举也可以使用它。

protocol Defaultable : RawRepresentable {
    static var defaultValue : Self { get }
}

protocol IntDefaultable : Defaultable where RawValue == Int {
}

extension IntDefaultable {
    static func value(for intValue : Int) -> Self {
        return Self.init(rawValue: intValue) ?? Self.defaultValue
    }

    static func value(for num : NSNumber?) -> Self {
        if let iVal = num?.intValue {
            return self.value(for: iVal)
        }
        return Self.defaultValue
    }
}

在定义了Defaultable协议之后,我可以创建一个IntDefaultable协议,用于Int枚举。

在IntDefaultable的扩展中,我可以创建通用代码来处理转换。首先,我创建一个带Int的函数。然后我创建一个NSNumber可选的函数。

接下来,看看如何构建其中一个枚举:

enum MetricType : Int, Codable, IntDefaultable { case inches, metric
    static var defaultValue: MetricType = .inches
}

我还决定声明枚举Codable,这可能很有用。当我添加IntDefaultable协议时,使用代码完成添加defaultValue代码行变得相当容易 - 转到新行并键入“def”-tab,然后键入“=。”,然后从中选择一个值弹出。请注意,我经常要选择第一个枚举值,但默认值可以是任何一个。

最后一件事就是调用转换例程来获取CoreData的值

let units = MetricType.value(for: self.metricType)  // where self.metricType is the NSManagedObject member.

答案 1 :(得分:1)

您可以在enum中添加初始值设定项。

enum PaperOrientation : Int { 
    case portrait, landscape

    init(number: NSNumber) {
        self = PaperOrientation(rawValue: number.intValue) ?? .portrait
    }
}