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
// }
}
}
- 对于 Identifiable :
在 Swift 中,Identifiable 是一个协议,它要求遵循它的类型必须提供一个属性 id,用于标识该类型的唯一性。通常,id 属性是一个可以唯一标识该类型的值,比如字符串、整数或者其他可哈希的类型。
在你的例子中,你的枚举类型 Sheet 遵循了 Identifiable 协议,并提供了一个计算型属性 id,该属性返回枚举成员的原始值(raw value)。这意味着每个枚举成员都有一个唯一的标识符,其取值即为对应的原始值。
这对于在 Swift 中使用涉及到 Identifiable 的视图或集合类型时非常有用。例如,如果你想要在 SwiftUI 中使用 List 或者 ForEach 来显示枚举类型的值,或者在其他需要唯一标识的场景中使用该枚举类型,遵循 Identifiable 协议可以使得操作更加方便。
- 对于 Equatable:
在这个 CropType 枚举中,虽然它遵循 Equatable 协议,但并没有显式地提供对应的 static func == (lhs: Self, rhs: Self) -> Bool 方法。在 Swift 中,当你的类型遵循 Equatable 协议时,编译器会自动生成默认的相等性判断方法。这个默认的实现会逐一比较类型的每个成员。
在你的 CropType 中,由于每个成员都是可以比较的(例如,CGFloat 和 Bool 都是可比较的),Swift 编译器能够为你的枚举类型自动生成默认的相等性判断方法。
如果你的枚举类型包含自定义的非可比较类型成员,或者你希望进行更复杂的相等性判断,你可以选择手动提供 static func == 方法,覆盖默认的实现。
网友评论