不同类型的SWIFT枚举关联值

Swift enum associated value with different types(不同类型的SWIFT枚举关联值)
本文介绍了不同类型的SWIFT枚举关联值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个这样的SWIFT枚举:

public enum AnimationType {

    case position(Float)
    case position([Keyframe<Float>])
    case scale(Float)
    case scale([Keyframe<Float>])
    case rect(CGRect)
    case rect([Keyframe<CGRect>])
    case transform(CGAffineTransform)
    case transform([Keyframe<CGAffineTransform>])
    ...
    ...
}
我们可以看到,对于每种类型,有两个可能的值-类型T的固定值或具有值类型T的关键帧数组([KeyFrame])。我想知道是否可以做些什么来避免在枚举中重复相同的名称,并合并两种枚举大小写类型?还是我用错误的方式模拟它?

推荐答案

我会为每种变体使用Kind枚举类型来解决此问题。

public enum AnimationType {
    public enum Kind<Value> {
        case scalar(Value)
        case keyframes([Keyframe<Value>])
    }

    case position(Kind<Float>)
    case scale(Kind<Float>)
    case rect(Kind<CGRect>)
    case transform(Kind<CGAffineTransform>)
}

用法:

let anim1 = AnimationType.position(.scalar(10))
let anim2 = AnimationType.position(.keyframes([Keyframe(10)]))

获取值:

switch anim1 {
case .position(let kind):
    switch kind {
    case .scalar(let value):
        print("value: (value)")
    case .keyframes(let keyframes):
        print("keyframes: (keyframes)")
    }

default: // You would implement the rest
    break
}
switch anim1 {
case .position(.scalar(let value)):
    print("value: (value)")

case .position(.keyframes(let keyframes)):
    print("keyframes: (keyframes)")

default: // You would implement the rest
    break
}
if case .position(.scalar(let value)) = anim1 {
    print("value: (value)")
}

您还可以添加Codable一致性:

public struct Keyframe<Value: Codable> {
    let value: Value

    init(_ value: Value) {
        self.value = value
    }
}

extension Keyframe: Codable {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(value)
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        value = try container.decode(Value.self)
    }
}
public enum AnimationType {
    public enum Kind<Value: Codable> {
        case scalar(Value)
        case keyframes([Keyframe<Value>])
    }

    case position(Kind<Float>)
    case scale(Kind<Float>)
    case rect(Kind<CGRect>)
    case transform(Kind<CGAffineTransform>)
}

extension AnimationType.Kind: Codable {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()

        switch self {
        case .scalar(let value): try container.encode(value)
        case .keyframes(let keyframes): try container.encode(keyframes)
        }
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()

        if let scalar = try? container.decode(Value.self) {
            self = .scalar(scalar)
            return
        }
        if let keyframes = try? container.decode([Keyframe<Value>].self) {
            self = .keyframes(keyframes)
            return
        }

        // You should throw error here instead
        fatalError("Failed to decode")
    }
}

extension AnimationType: Codable {
    private enum CodingKeys: CodingKey {
        case position
        case scale
        case rect
        case transform
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)

        switch self {
        case .position(let kind): try container.encode(kind, forKey: .position)
        case .scale(let kind): try container.encode(kind, forKey: .scale)
        case .rect(let kind): try container.encode(kind, forKey: .rect)
        case .transform(let kind): try container.encode(kind, forKey: .transform)
        }
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        if let position = try? container.decode(Kind<Float>.self, forKey: .position) {
            self = .position(position)
            return
        }
        if let scale = try? container.decode(Kind<Float>.self, forKey: .scale) {
            self = .scale(scale)
            return
        }
        if let rect = try? container.decode(Kind<CGRect>.self, forKey: .rect) {
            self = .rect(rect)
            return
        }
        if let transform = try? container.decode(Kind<CGAffineTransform>.self, forKey: .transform) {
            self = .transform(transform)
            return
        }

        // You should throw error here instead
        fatalError("Failed to decode")
    }
}

编码示例:

do {
    let data = try JSONEncoder().encode(anim1)
    if let str = String(data: data, encoding: .utf8) {
        print(str)
        // Prints: {"position":10}
    }
} catch {
    print(error)
}

anim2返回{"position":[10]}的情况相同。

这篇关于不同类型的SWIFT枚举关联值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Why local notification is not firing for UNCalendarNotificationTrigger(为什么没有为UNCalendarNotificationTrigger触发本地通知)
iOS VoiceOver functionality changes with Bundle Identifier(IOS画外音功能随捆绑包标识符而变化)
tabbar middle tab out of tabbar corner(选项卡栏中间的选项卡角外)
Pushing UIViewController above UITabBar(将UIView控制器推送到UITabBar上方)
Dropbox Files.download does not start when number of files in folder is gt; 1000(当文件夹中的文件数为1000时,Dropbox Files.Download不会启动)
How can I sync two flatList scroll position in react native(如何在本机Reaction中同步两个平面列表滚动位置)