gpt4 book ai didi

ios - 符合 Equatable for Diffing 的协议(protocol)

转载 作者:行者123 更新时间:2023-11-29 05:22:10 25 4
gpt4 key购买 nike

我这里有一个小型聊天应用程序。

我可以有两种类型的消息: - 文本 - 视频

我在解码 JSON 时使用多态性,如下所示:

import Foundation

enum MessageType: Int, Decodable {
case text
case video
}

protocol Message: Decodable {
static var type: MessageType { get }
var id: String { get }
var user: User { get}
var timestamp: String { get }
}

struct TextMessage: Message {
static var type: MessageType = .text
var id: String
var user: User
var timestamp: String
let text: String
}

struct VideoMessage: Message {
static var type: MessageType = .video
var id: String
var user: User
var timestamp: String
let text: String
let link: String
let poster: String
}

enum MessageWrapper: Decodable {

enum CodingKeys: String, CodingKey {
case type
}

case text(TextMessage)
case video(VideoMessage)

var item: Message {
switch self {
case .text(let item): return item
case .video(let item): return item
}
}

init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let type = try values.decode(Int.self, forKey: .type)
switch type {
case MessageType.text.rawValue: self = .text(try TextMessage(from: decoder))
case MessageType.video.rawValue: self = .video(try VideoMessage(from: decoder))
default:
throw DecodingError.dataCorruptedError(forKey: .type,
in: values,
debugDescription: "Invalid type")
}
}
}

我也在使用 MVVM 方法,如下所示:

struct ChatViewModel {

enum ViewModelType {
case loading
case text(TextMessageViewModel)
case video(VideoMessageViewModel)
case failure(ErrorViewModel)
}

enum State {
case initialized
case loading
case loaded([Message])
case failed(Error)
}

let state: State
let viewModels: [ViewModelType]

init(with state: State) {
self.state = state
switch state {
case .initialized:
viewModels = []
case .loading:
viewModels = [
.loading,
]
......
}
}

为了能够使用 Diffing 库,如 DifferChatViewModel 应符合 Equatable 协议(protocol)。

extension ChatViewModel: Equatable {
static func == (lhs: ChatViewModel, rhs: ChatViewModel) -> Bool {
return lhs.state == rhs.state
}
}

extension ChatViewModel.State: Equatable {
static func == (lhs: ChatViewModel.State, rhs: ChatViewModel.State) -> Bool {
switch (lhs, rhs) {
case (.initialized, .initialized): return true
case (.loading, .loading): return true
case let (.loaded(l), .loaded(r)): return l == r
case let (.failed(l), .failed(r)): return l.localizedDescription == r.localizedDescription
default: return false
}
}
}

这里的问题是 case let (.loaded(l), .loaded(r)): return l == r, Message 作为协议(protocol),不符合Equatable

使其符合Equatable,例如

protocol Message: Decodable, Equatable {
static var type: MessageType { get }
var id: String { get }
var user: User { get}
var timestamp: String { get }
}

产生错误协议(protocol)“Message”只能用作通用约束,因为它对 MessageWrapper 有 Self 或关联类型要求:

enum MessageWrapper: Decodable {

...

var item: Message { // Protocol 'Message' can only be used as a generic constraint because it has Self or associated type requirements
switch self {
case .text(let item): return item
case .video(let item): return item
}
}

...
}

有什么想法或建议可以有一个干净的方法来解决这个问题吗?我看到了一些关于类型删除的帖子,但经过一些测试后,我不确定它是否真正解决了问题。

最佳答案

您不必遵守 Equatable 即可使用 == 运算符。您可以自己定义一个这样的运算符,而无需遵守 Equatable

为了方便起见,我假设 TextMessageVideoMessage 已经符合 Equatable

首先,编写一个比较 Message 的方法:

func messageEqual(m1: Message, m2: Message) -> Bool {
if let textMessage1 = m1 as? TextMessage, let textMessage2 = m2 as? TextMessage {
return textMessage1 == textMessage2
}
if let videoMessage1 = m1 as? VideoMessage, let videoMessage2 = m2 as? VideoMessage {
return videoMessage1 == videoMessage2
}
return false
}

然后是 [Message]== 运算符:

func ==(messages1: [Message], messages2: [Message]) -> Bool {
return messages1.count == messages2.count &&
zip(messages1, messages2).allSatisfy(messageEqual)
}

现在 l == r 应该可以编译了。

关于ios - 符合 Equatable for Diffing 的协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58580011/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com