嵌套的Struct模型不会导致视图重新呈现SwiftUI

时间:2020-07-13 00:08:47

标签: swiftui

我有一个视图,可以通过和ObservableObject监听模型:

class Feed : ObservableObject {
    
    // Posts to be displayed
    @Published var 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
}

其中包含其他多个Struct模型,例如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直接有关?

1 个答案:

答案 0 :(得分:0)

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

更新的代码(在新结构中添加了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()
    }
}