当对象属性发生变化时,ObservedRealmObject 不会使视图失效

问题描述 投票:0回答:1

我之前没有广泛使用过 RealmSwift,所以也许我的问题的解决方案可能相当微不足道。我一直在尝试配置下面的

GroupView
,使其反映其
group
ObservedObject 的状态。请注意,视图绑定到 AsyncImage 初始值设定项中的
photo._url
,目的是在修改照片的 url 时重新评估视图。

import SwiftUI
import RealmSwift

struct GroupView: View {
    @Environment(\.realmUser) var user //custom environment key
    @ObservedRealmObject var group: Group
    var body: some View {
            HStack(spacing: 20){
                ForEach((group.groupContent?.tableContent?.photos)!,id: \.id){ photo in
                    AsyncImage(url: URL(string: photo._url)){ phase in
                        switch phase{
                        case .success(let image):
                            image
                                .resizable()
                                .scaledToFit()
                        case .failure:
                            Text("Image not found").task {
                                 if let user = user{
                                    await photo.refreshURLIfNeeded(user: user)
                                }
                            }
                        case .empty:
                            ProgressView()
                        }
                    }.task{
                        if let user = user{
                            let _ = await photo.refreshURLIfNeeded(user:user)
                        }
                       
                      }
                }
            }
        
    }
}

出现问题的原因是,即使在

group.groupContents?.tableContent?.photos
EmbeddedObject 中的照片的 _url 属性通过调用
photo.refreshPhotoURL(user:User)
更新后,AsyncImageView 也没有被重新评估(我已经验证了 url)正在使用 Atlas 控制台中的有效照片链接进行更新,因此空/无效的 url 不是罪魁祸首)。由于绑定
$group
在refreshPhotoURL的主体中不直接可用,因此解冻后通过realm!.write{}事务执行更新,遵循realm的执行显式写入的示例。

extension Photo{
func refreshURLIfNeeded(user: User) async{
//Call serverless Atlas function for new URL
   let urlString = try? await user.functions.refreshURL([AnyBSON(self.id!)]).stringValue
    
let realm = self.realm!.thaw()
        try! realm.write{
            self.thaw()!._url = urlString ?? ""
        }
        
        
    }
}
final class Group: Object,ObjectKeyIdentifiable{
    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var groupContent: GroupContent?
}

final class GroupContent: EmbeddedObject{
    @Persisted var tableContent: TableContent?
}

final class tableContent:EmbeddedObject{ 
    @Persisted var photos: List<Photo>
}

在 Atlas Console 中手动更改

_url
属性也会导致活动
GroupView
中无响应/失效。即使修改了观察到的嵌入属性的值,也可能导致 AsyncImageViews 保持不变
group

编辑:

该问题似乎与嵌入无关,因为将

TableContent
设置为对象而不是嵌入对象并将其传递到 GroupView 中代替
group
仍然会导致视图不更新。

ios swift realm
1个回答
0
投票

正如我编辑的问题中提到的,实例是顶级

Objects
EmbeddedObject
与问题的根本原因关系不大。相反,上面面临的问题根源于 RealmSwift
@ObservedRealmObject 属性包装器的实现,它本身依赖于 SwiftUI 的
@ObservedObject
属性包装器来提供其持久/无效功能。

为了捕获

@ObservedRealmObject
发生的问题,我生成了以下包含嵌套 ObservableObjects 的示例:

@ObservedObject 行为(Swift 5.8 和 SwiftUI 4.0)

 class ObserveMe:ObservableObject{
    @Published var observeMeOnceMore = ObserveMeOnceMore() 
}
class ObserveMeOnceMore:ObservableObject{
    @Published var counter = 0
}

struct ContentView: View {
    @ObservedObject var observeMe = ObserveMe()
    var body: some View {
       
            Button("Does not publish: \(observeMe.observeMeOnceMore.counter)"){
                observeMe.observeMeOnceMore.counter += 1 //Change not published to view since observation does not occur at the level of @ObserveMeOnceMore
                print(observeMe.observeMeOnceMore.counter)
            }
        CounterView(observeMeOnceMore: observeMe.observeMeOnceMore)
        
    }
}

struct CounterView:View{
    @ObservedObject var observeMeOnceMore: ObserveMeOnceMore
    var body:some View{
        Button("Does publish: \(observeMeOnceMore.counter)"){
            observeMeOnceMore.counter += 1
            print(observeMeOnceMore.counter) //Works as expected
        }
    }
}

在写这个答案的过程中,我还发现了@lorem-ipsum的这个答案,这似乎反映了包含ObservableObject实例的Views中发生的不适当的观察

级别
的常见问题。

@ObservedObject
的观察级别原则应用于
@ObservedRealmObject
,创建一个单独的
PhotoView
,它直接接受
EmbeddedObject
作为参数,以实现 GroupView 所需的精确观察的级别。唯一棘手的细节是,EmbeddedObject(或对象)必须符合
ObjectKeyIdentifiable
才能由
@ObservedRealmObject
属性包装器绑定(编译器警告,
No exact matches in call to initializer
。我已提交了 功能请求 来改进编译器警告,但暂时不是主要问题。

© www.soinside.com 2019 - 2024. All rights reserved.