【问题标题】:Nested Struct models not causing view to re-render SwiftUI嵌套结构模型不会导致视图重新渲染 SwiftUI
【发布时间】:2020-07-13 00:08:47
【问题描述】:

我有一个通过 ObservableObject 监听模型的视图:

class Feed : ObservableObject {
    
    // Posts to be displayed
    @Published var posts = [Posts]()
    ...
    ...
}

Posts 模型如下所示:

struct Posts: Hashable, Identifiable {
    let bar: Bars
    let time: String
    var description: String
    let id: String
    let createdAt : String
    let tags : [Friends]
    let groups : [String]
    var intializer : Friends    // Creator of the post
}

其中包含多个其他结构模型,例如 Friends 和 Bars。但是,当我在这些其他模型之一中更改值时,它不会触发 @Published 触发,因此不会重绘视图。例如,Friends 模型如下所示:

struct Friends : Hashable {
    
    static func == (lhs: Friends, rhs: Friends) -> Bool {
        return lhs.id == rhs.id
    }
    
    let name: String
    let username: String
    let id : String
    var thumbnail : UIImage?
    var profileImgURL : String?
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}

但是当我更改缩略图时,视图不会重绘。但是,当我直接在 Posts 模型之外更改某些内容时,例如 description 属性,视图会被重绘。当基础模型值发生更改时,如何重绘视图?

我如图所示更改缩略图:

        // Grab the thumbnail of user (if exists)
        if post.intializer.profileImgURL != nil {
            AF.request(post.intializer.profileImgURL!, method: .get, encoding: URLEncoding.default)
                .validate()
                .responseData { (response) in
                    if let data = response.value {
                        // Find the index of where this post is in the array and set the profile img
                        if let indexOfPost = self.posts.firstIndex(of: post) {
                            self.posts[indexOfPost].intializer.thumbnail = UIImage(data: data)
                        }
                    }
            }
        }

但如果我要更改描述做同样的事情:

        // Grab the thumbnail of user (if exists)
        if post.intializer.profileImgURL != nil {
            AF.request(post.intializer.profileImgURL!, method: .get, encoding: URLEncoding.default)
                .validate()
                .responseData { (response) in
                    if let data = response.value {
                        // Find the index of where this post is in the array and set the profile img
                        if let indexOfPost = self.posts.firstIndex(of: post) {
                            self.posts[indexOfPost].description = "Loaded!!!!"
                        }
                    }
            }
        }

当我这样做时,视图确实会更新和更改。我也可以看到缩略图被正确加载,因为我可以打印出发送的数据,有时缩略图会正确地为视图重绘。

编辑

按照建议,我尝试在结构中添加一个变异函数:

struct Posts: Hashable, Identifiable {
    let bar: Bars
    let time: String
    var description: String
    let id: String
    let createdAt : String
    let tags : [Friends]
    let groups : [String]
    var intializer : Friends    // Creator of the post
    
    mutating func addInitThumbnail(img : UIImage) {
        self.intializer.thumbnail = img
    }
}

然后使用它:

    func grabInitThumbnail(post : Posts) {
        // Grab the thumbnail of user (if exists)
        if post.intializer.profileImgURL != nil {
            AF.request(post.intializer.profileImgURL!, method: .get, encoding: URLEncoding.default)
                .validate()
                .responseData { (response) in
                    if let data = response.value {
                        // Find the index of where this post is in the array and set the profile img
                        if let indexOfPost = self.posts.firstIndex(of: post) {
                            if let thumbnailImg = UIImage(data: data) {
                                self.posts[indexOfPost].addInitThumbnail(img: thumbnailImg)
                            }
                        }
                    }
            }
        }
    }

但它也不起作用。

但是,当我这样做时:

    func grabInitThumbnail(post : Posts) {
        // Grab the thumbnail of user (if exists)
        if post.intializer.profileImgURL != nil {
            AF.request(post.intializer.profileImgURL!, method: .get, encoding: URLEncoding.default)
                .validate()
                .responseData { (response) in
                    if let data = response.value {
                        // Find the index of where this post is in the array and set the profile img
                        if let indexOfPost = self.posts.firstIndex(of: post) {
                            self.posts[indexOfPost].intializer.thumbnail = UIImage(data: data)
                            self.posts[indexOfPost].description = "Loaded!!!!"
                        }
                    }
            }
        }
    }

图像已加载并正确设置...?所以我认为它可能与 UIImages 直接有关?

【问题讨论】:

  • 当您说“我更改缩略图”时,您是在设置新的缩略图,还是在更改 UIImage 的属性?
  • 将缩略图从 nil 设置为 UIImage。
  • 您能否展示一下您是如何更改缩略图值的? @JakeMaschoff
  • @Zeona 我在如何更改缩略图值的问题中添加了,如果有帮助请告诉我
  • @JakeMaschoff 请尝试使用mutating 来检查更新是否有效。例如,添加一个变异函数来更改结构内的缩略图并调用该函数。变异函数 updateThumbnail(thumbnail: UIImage) { self.thumbnail = thumbnail)

标签: swiftui


【解决方案1】:

我尝试使用变异函数并直接更新值,这两种情况都有效。

更新代码(在新结构中添加 UIImage)

import SwiftUI
import Foundation

//Employee
struct Employee : Identifiable{

    var id: String = ""
    var name: String = ""
    var address: Address
    var userImage: UserIcon
    
    init(name: String, id: String, address: Address, userImage: UserIcon) {
        self.id = id
        self.name = name
        self.address = address
        self.userImage = userImage
    }
    
    mutating func updateAddress(with value: Address){
        address = value
    }
}

//User profile image
struct UserIcon {
    var profile: UIImage?
    
    init(profile: UIImage) {
        self.profile = profile
    }
    
    mutating func updateProfile(image: UIImage) {
        self.profile = image
    }
}

//Address
struct Address {

    var houseName: String = ""
    var houseNumber: String = ""
    var place: String = ""
    
    init(houseName: String, houseNumber: String, place: String) {
        self.houseName = houseName
        self.houseNumber = houseNumber
        self.place = place
    }
    
    func getCompleteAddress() -> String{
        let addressArray = [self.houseName, self.houseNumber, self.place]
        return addressArray.joined(separator: ",")
    }
}

//EmployeeViewModel
class EmployeeViewModel: ObservableObject {
    @Published var users : [Employee] = []
    
    func initialize() {
        self.users = [Employee(name: "ABC", id: "100", address: Address(houseName: "Beautiful Villa1", houseNumber: "17ABC", place: "USA"), userImage: UserIcon(profile: UIImage(named: "discover")!)),
        Employee(name: "XYZ", id: "101", address: Address(houseName: "Beautiful Villa2", houseNumber: "18ABC", place: "UAE"), userImage: UserIcon(profile: UIImage(named: "discover")!)),
        Employee(name: "QWE", id: "102", address: Address(houseName: "Beautiful Villa3", houseNumber: "19ABC", place: "UK"), userImage: UserIcon(profile: UIImage(named: "discover")!))]
    }
    
    
    func update() { //both below cases worked
        self.users[0].address.houseName = "My Villa"
        //self.users[0].updateAddress(with: Address(houseName: "My Villa", houseNumber: "123", place: "London"))
        self.updateImage()
    }
    
    func updateImage() {
        self.users[0].userImage.updateProfile(image: UIImage(named: "home")!)
    }
}
    
//EmployeeView
struct EmployeeView: View {
    @ObservedObject var vm = EmployeeViewModel()
    
    var body: some View {
       NavigationView {
            List {
                ForEach(self.vm.users) { user in
                    VStack {
                        Image(uiImage: user.userImage.profile!)
                        Text("\(user.name) - \(user.address.getCompleteAddress())")
                    }
                }.listRowBackground(Color.white)
            }.onAppear(perform: fetch)
            .navigationBarItems(trailing:
                Button("Update") {
                    self.vm.update()
                }.foregroundColor(Color.blue)
            )
             .navigationBarTitle("Users", displayMode: .inline)
        
       }.accentColor(Color.init("blackTextColor"))
    }
    
    func fetch() {
        self.vm.initialize()
    }
}

【讨论】:

  • 所以我尝试了这个并且它有效,但是第二次我将嵌套字段设置为 UIImage,它没有更新......所以我认为它与 UIImage 直接有关?
  • @JakeMaschoff 我尝试过使用图片,效果也很好。我不知道你到底是什么问题。我将添加我更新的代码。请检查一下。
  • 这很好用。将mutating 添加到结构的update 方法修复了我的重新渲染问题。
猜你喜欢
  • 1970-01-01
  • 2015-01-11
  • 2021-01-17
  • 2018-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多