SwiftUI某些更新逻辑与Equatable协议的依赖
SwiftUI某些更新逻辑与Equatable协议的依赖

SwiftUI某些更新逻辑与Equatable协议的依赖

SwiftUI 的某些更新逻辑依赖于 Equatable 协议,当两个对象被Equatable协议判断为相等时,SwiftUI则会跳过更新,导致UI不刷新。

示例描述

例如,在修改地图点描述时,会存在无法保存成功的问题。

代码逻辑

在编辑视图中,地图点的信息从外面视图中传递进来的,当点击编辑视图的保存按钮时,会将修改的name和description字段复制给传递进来的地图点。

当前的问题在于,修改字段后,无法通过保存按钮将数据返回给地图视图。

问题代码为

struct Location: Codable, Equatable, Identifiable {
    static func == (lhs: Location, rhs: Location) -> Bool {
        return lhs.id == rhs.id
        
    }
    let id: UUID
    var name: String
    var description: String
    var latitude: Double
    var longitude: Double
    ...
}

因为Location自定义的Equatable协议导致的,Location在定义是考虑到id是不可变的,所以id为常量且不可修改,所以自定义Equatable协议时,以作为判断是否为同一个对象。

这是因为id为UUID,UUID一致就可以默认为同一个对象,所以Equatable不需要再对比其他的元素,简化了对比方法。

但是在调用流程中,传入到编辑视图的对象修改标题和描述后,重新传给地图视图(ContentView),SwiftUI会根据Equatable协议判断两个对象是否相等,如果被判定为相等的话,Swift会跳过更新,导致UI不更新,也因此出现修改标题或描述后,仍然没有显示的原因。

因此,解决方案为修改Equatable协议,将name、description也作为是否相等进行对比

static func == (lhs: Location, rhs: Location) -> Bool {
    return lhs.id == rhs.id &&
    lhs.name == rhs.name &&
    lhs.description == rhs.description
}

这样,在修改视图返回对象时,发现name或者description不相等,SwiftUI进行更新,UI更新为修改后的name和description。

另一种解决方案为

var id: UUID

将id字段改为可修改的变量。

在编辑视图中,将传入的对象的id设置一个新的UUID:

Button("Save") {
    var newLocation = location
    newLocation.id = UUID()
    newLocation.name = name
    newLocation.description = description
    onSave(newLocation)
    dismiss()
}

这样,再重新传回地图视图时,因为修改后的对象被赋予了一个新的UUID,因此SwiftUI认为两个对象不相等,SwiftUI进行更新操作。

以上就是本文的全部内容,通过Equatable协议简化对比后,可能会对重新修改的数据带来一些困扰,但是仍然可以通过修改Equatable协议或者将修改的对象属性进行调整,来完成对SwiftUI的更新。

相关文章

Selecting and editing map annotations:https://www.hackingwithswift.com/books/ios-swiftui/selecting-and-editing-map-annotations

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注