Swift 枚举示例

2024-03-04  本文已影响0人  大成小栈
1. 带关联属性的枚举

定义一个枚举类型:

    enum ContentState: Equatable {
        case `default`
        case text(text: String, language: String)
        case voice(path: String)
        
        var name: String {
            switch self {
            case .default:
                ""
            case .text:
                "text"
            case .voice:
                "voice"
            }
        }
    }

实例化一个枚举类型的变量:

var contentState: ContentState = .default

switch-case 一个枚举变量:

func updateTemplate(state: ContentState) -> Template? {
            guard let template else { return nil }
            switch state {
            case .default:
                break
            case let .text(text, language, voice):
                template.ptInfos = [PTInfo(audioUrl: "", context: text, voiceEgineId: voice?.engineId ?? "", type: state.name, language: language)]
            case let .audio(_, serverPath):
                template.ptInfos = [PTInfo(audioUrl: serverPath, context: "", voiceEgineId: "", type: state.name, language: "")]
                
            }
            return template
        }

其主要作用是,可携带多个关联属性,而enum中的“var name:”才是最终的枚举实际值。
注意:其中枚举的关联属性、关联参数的使用,对应和传递的恰到好处。

示例:

import Foundation

public enum AspectRatio {
    case original
    case freeForm
    case square
    case ratio(width: Int, height: Int)

    var rotated: AspectRatio {
        switch self {
        case let .ratio(width, height):
            return .ratio(width: height, height: width)
        default:
            return self
        }
    }

    var description: String {
        switch self {
        case .original:
            return "ORIGINAL"
        case .freeForm:
            return "FREEFORM"
        case .square:
            return "SQUARE"
        case let .ratio(width, height):
            return "\(width):\(height)"
        }
    }
}

// MARK: Codable

extension AspectRatio: Codable {
    enum CodingKeys: String, CodingKey {
        case description
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        guard let desc = try container.decodeIfPresent(String.self, forKey: .description) else {
            self = .freeForm
            return
        }
        switch desc {
        case "ORIGINAL":
            self = .original
        case "FREEFORM":
            self = .freeForm
        case "SQUARE":
            self = .square
        default:
            let numberStrings = desc.split(separator: ":")
            if numberStrings.count == 2,
                let width = Int(numberStrings[0]),
                let height = Int(numberStrings[1]) {
                self = .ratio(width: width, height: height)
            } else {
                self = .freeForm
            }
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(description, forKey: .description)
    }
}

extension AspectRatio: Equatable {
    public static func == (lhs: AspectRatio, rhs: AspectRatio) -> Bool {
        switch (lhs, rhs) {
        case (let .ratio(lhsWidth, lhsHeight), let .ratio(rhsWidth, rhsHeight)):
            return lhsWidth == rhsWidth && lhsHeight == rhsHeight
        case (.original, .original),
             (.freeForm, .freeForm),
             (.square, .square):
            return true
        default:
            return false
        }
    }
}

// 调用
cropper.setAspectRatio(AspectRatio.ratio(width: ratioW, height: ratioH))
2. 普通的枚举

枚举中定义的是变量:

public enum Config {
    public static var croppingImageShortSideMaxSize: CGFloat = 1280
    public static var croppingImageLongSideMaxSize: CGFloat = 5120 // 1280 * 4

    public static var highlightColor = UIColor(red: 249 / 255.0, green: 214 / 255.0, blue: 74 / 255.0, alpha: 1)

    public static var resourceBundle = Bundle(for: CropperViewController.self)
}

// 用法
button.setTitleColor(ImageCropper.Config.highlightColor, for: .normal)

枚举定义错误,用于 throw :

enum AlertType {
        case alertStr1
        case alertStr2
    }

// 定义
enum Checked: Swift.Error {
    case network
    case paramsInvalid
    case alert(AlertType) // enum可嵌套啊!
}

// throw
private func preCheckNetwork() throws { // 网络判断
    guard HXNetworkingManager.checkNetworkEnable() else {
        throw Checked.network
    }
}

private func preCheckParams(_ config: SynthesizingConfig) throws { // 入参判断
    guard config.isValidFaceInfos() else {
        throw Checked.paramsInvalid
    }
}

// try-catch 刚刚定义的 throw 方法
do {
    // 可连续try 
    try preCheckNetwork()
    try preCheckParams(config)
    
    // 继续其他操作
    await start(with: navigationController, config: config, isNeedAD: false)
} catch Checked.network {
    await CommonAlertView(messageWaningOfflineAlert: ()).show()
} catch Checked.paramsInvalid {
    await MainActor.run {
        MBProgressHUD.showMessage("Please choose appropriate photo again.".localized)
    }
} catch {
    
}

基于moya-alamofire的api封装:

enum CreativeWorkAPI {
    
    /// 删除作品
    case delete(workId: String)
    
}

extension CreativeWorkAPI: APITarget {
    
    var route: APIRoute {
        switch self {
        case .delete:
            return .post("/work/delete_work")
        }
    }
    
    var parameters: APIParameters? {
        switch self {
        case let .delete(workId):
            return ["id": workId]
        }
    }
    
}

extension CreativeWorkAPI: APIProviderSharing {
    
    static var shared = APIProvider<CreativeWorkAPI>()
    
}

// 调用
// 服务端
CreativeWorkAPI.shared
    .publisher(.delete(workId: workId), type: APIEmptyResult.self)
    .loading("")
    .receive(on: DispatchQueue.main)
    .sink(
        // 回调
    )
    .store(in: &cancellables)

数据 model 的解析:

struct UserVoiceList: Decodable {
    
    @Default<Int> var createNumLeft: Int = 0
    @Default<[String]> var languageList: [String] = []
    @Default<[String]> var languageAlertList: [String] = []
    var voiceList: [VoiceItem]? = []
    
    private enum CodingKeys: String, CodingKey {
        case createNumLeft = "create_num_left"
        case languageList = "language_list"
        case languageAlertList = "language_alert_list"
        case voiceList = "voice_list"
    }
}

struct VoiceItem: Decodable {
    
    @Default<String> var audioId: String = ""
    @Default<String> var name: String = ""
    @Default<String> var audioUrl: String = ""
    @Default<String> var cover: String = ""
    @Default<String> var voicEngineId: String = ""
    @Default<String> var status: String = "" //"SUCCESS"  ||  "ERROR" || "DEMO_ERROR"
    
    let id = UUID()
    
    var isNew: Bool = false
    
    var audioState: VoiceAudioActionType = .paused
    
    private var _synthesisState: VoiceSynthesisStateType = .success
    var synthesisState: VoiceSynthesisStateType {
        get {
            if audioUrl.isEmpty {
                return status == "SUCCESS" ? .training : .failed
            } else {
                return _synthesisState
            }
        }
        set {
            _synthesisState = newValue
        }
    }
    
    private enum CodingKeys: String, CodingKey {
        case audioId = "audio_id"
        case name
        case audioUrl = "audio_url"
        case cover
        case voicEngineId = "voice_engine_id"
        case status
    }
    
    init() {
        
    }

}

枚举也是可以遵循协议:

protocol LogMonitorKeyProtocol where Self: RawRepresentable, RawValue == String {
    static var prefix: String { get }
}

extension LogMonitorKeyProtocol { // 协议还可以被扩展
    var value: String {
        "app_monitor" + "_dreamface_" + Self.prefix + "_" + self.rawValue
    }
}

struct LogMonitorKey {
        
    enum launch: String, LogMonitorKeyProtocol {
        static var prefix = "launch"
        case launch      // ✅
    }
    
    enum stable: String, LogMonitorKeyProtocol {
        static var prefix = "stable"
        case crash      // ✅
        case catch_crash      // ✅
        case stuck      // ❌
    }
    
    enum performance: String, LogMonitorKeyProtocol {
        static var prefix = "performance"
        case cpu      // ❌
        case memory      // ❌
    }
}

如果想兼容oc中的枚举:

@objc public enum PlayerState: Int {
    case resetted = 0
    case playing = 1
    case paused = 2
    case finished = 3
}

定义 enum 时,后面的关键字:

类型:空、Error、Int、String 等
协议:Equatable、Comparable、Identifiable、CodingKey、Hashable等

// 1. 以Identifiable协议为例
enum Sheet: String, Identifiable {
    case autoTranslate, speechVoice, languageMismatch
    
    var id: String { rawValue }
}

struct ContentView: View {
    let sheets: [Sheet] = [.autoTranslate, .speechVoice, .languageMismatch]

    var body: some View {
        List(sheets) { sheet in
            Text(sheet.rawValue)
        }
    }
}


// 2. 以Equatable协议为例
enum CropType: Equatable {
    case normal
    case bust(isPet: Bool)
    case aigcVideoPag(ratio: CGFloat)
    case aigcVideo(renderWidth: CGFloat)
    case aigcImagePag(ratio: CGFloat)
    // case aigcImage(renderWidth: CGFloat)
    case pag(ratio: CGFloat)
    case anything
    case aigc(ratio: CGFloat, isPickHead: Bool)
    
    var value: String {
        switch self {
        case .bust(let isPet):
            return isPet ? "pet" : "person"
        default:
            return "nothing"
        }
    }
    
    static func == (lhs: CropType, rhs: CropType) -> Bool {
        // 如果使用了value,作为最终值
        return lhs.value == rhs.value
        
        // 如果仍然按照类型、参数逐一比对
//            switch (lhs.value, rhs.value) {
//            case (.normal, .normal):
//                return true
//            case let (.bust(isPet1), .bust(isPet2)):
//                return isPet1 == isPet2
//            // ... 其他枚举成员的比较逻辑 ...
//            default:
//                return false
//            }
    }   
}

在 Swift 中,Identifiable 是一个协议,它要求遵循它的类型必须提供一个属性 id,用于标识该类型的唯一性。通常,id 属性是一个可以唯一标识该类型的值,比如字符串、整数或者其他可哈希的类型。

在你的例子中,你的枚举类型 Sheet 遵循了 Identifiable 协议,并提供了一个计算型属性 id,该属性返回枚举成员的原始值(raw value)。这意味着每个枚举成员都有一个唯一的标识符,其取值即为对应的原始值。

这对于在 Swift 中使用涉及到 Identifiable 的视图或集合类型时非常有用。例如,如果你想要在 SwiftUI 中使用 List 或者 ForEach 来显示枚举类型的值,或者在其他需要唯一标识的场景中使用该枚举类型,遵循 Identifiable 协议可以使得操作更加方便。

在这个 CropType 枚举中,虽然它遵循 Equatable 协议,但并没有显式地提供对应的 static func == (lhs: Self, rhs: Self) -> Bool 方法。在 Swift 中,当你的类型遵循 Equatable 协议时,编译器会自动生成默认的相等性判断方法。这个默认的实现会逐一比较类型的每个成员。

在你的 CropType 中,由于每个成员都是可以比较的(例如,CGFloat 和 Bool 都是可比较的),Swift 编译器能够为你的枚举类型自动生成默认的相等性判断方法。

如果你的枚举类型包含自定义的非可比较类型成员,或者你希望进行更复杂的相等性判断,你可以选择手动提供 static func == 方法,覆盖默认的实现。

上一篇 下一篇

猜你喜欢

热点阅读