如何让LoadingState<Movie>遵循Equatable协议以解决SwiftUI task(id:)修饰符的报错问题
如何让LoadingState遵循Equatable协议以解决SwiftUI task(id:)修饰符的报错问题
嗨,这个问题很常见,原因是SwiftUI的task(id:)修饰符要求传入的id必须遵循Equatable协议——它需要通过比较前后值的变化来决定是否触发新的任务。你的LoadingState枚举目前还没有实现这个协议,所以才会抛出错误。下面给你两种可行的解决思路:
方法一:为LoadingState自定义Equatable实现
因为你的LoadingState里有Error类型的关联值,而Error本身并不遵循Equatable,所以Swift无法自动为枚举合成Equatable实现。我们可以手动实现==运算符,自定义比较逻辑:
// 首先让泛型T同时遵循Codable和Equatable enum LoadingState<T: Codable & Equatable>: Equatable { case none case loading case success(T) case error(Error) // 自定义Equatable的比较逻辑 static func == (lhs: LoadingState<T>, rhs: LoadingState<T>) -> Bool { switch (lhs, rhs) { // 无状态和加载状态直接匹配 case (.none, .none), (.loading, .loading): return true // 成功状态比较关联的Movie实例 case (.success(let lhsMovie), .success(let rhsMovie)): return lhsMovie == rhsMovie // 错误状态可以根据需求比较,比如比较错误描述或者类型 case (.error(let lhsError), .error(let rhsError)): return lhsError.localizedDescription == rhsError.localizedDescription // 其他情况都不相等 default: return false } } }
同时别忘了给Movie加上Equatable协议(Swift会自动为只包含String属性的结构体合成实现):
struct Movie: Codable, Equatable { let title: String }
这样修改后,LoadingState<Movie>就满足了Equatable的要求,task(id:)修饰符就能正常工作了。
方法二:使用遵循Equatable的自定义错误类型
如果你的业务场景允许,更优雅的方式是定义一个自定义的错误枚举,让它同时遵循Error和Equatable,这样Swift就能自动为LoadingState合成Equatable实现:
// 自定义可比较的错误类型 enum AppError: Error, Equatable { case networkFailure case dataParsingFailed case unknownError } // 修改LoadingState的error关联值为自定义错误 enum LoadingState<T: Codable & Equatable>: Equatable { case none case loading case success(T) case error(AppError) } // 同样给Movie加上Equatable struct Movie: Codable, Equatable { let title: String }
这种方式不需要手动写==方法,Swift会自动处理所有枚举 case 的比较,代码更简洁也更易维护。
备注:内容来源于stack exchange,提问作者john doe
相关产品推荐
相关产品推荐

