Swiftui ObservableObject with array not update view

Viewed 807

I have a problem with Array using ObservableObject in my view. I have an empty array. I call a function at page onAppear. When the data is returned, the view does not update with the new data in array:

class NewsState: ObservableObject {
    
    private let base: String = "api"
    let objectWillChange = ObservableObjectPublisher()
    
    @Published var wagsList: Array<UserSlider> = [] {
        willSet {
            objectWillChange.send()
        }
    }
    
    func getList() {
        let url = NSURL(string: "\(base)/UserApi/getList")
        var mutableURLRequest = URLRequest(url: url! as URL)
        mutableURLRequest.httpMethod = "GET"
        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
        AF.request(mutableURLRequest).responseData { response in
            guard let data = response.data else { return }
            let resp = try! JSONDecoder().decode(Array<UserSlider>.self, from: data)
            for i in resp {
                let userSlider = UserSlider(id: i.id, uid: i.uid, image: i.image)
                self.wagsList.append(userSlider)
            }
        }
    }
}

In my view I have this:

HStack {
    ScrollView(.horizontal, showsIndicators: false) {
        HStack(spacing: 20) {
            if(self.newsState.wagsList.count != 0) {
                ForEach(self.newsState.wagsList, id: \.self) { wags in
                    VStack {
                        HStack {
                            URLImage(URL(string: "\(wags.image)")!, expireAfter: Date(timeIntervalSinceNow: 10)) { proxy in
                                proxy.image
                                    .renderingMode(.original)
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                                    .frame(width: 60, height: 60)
                                    .clipShape(Circle())
                                    .overlay(
                                        RoundedRectangle(cornerRadius: 30)
                                            .stroke(Color.white, lineWidth: 2)
                                    )
                                    .contentShape(Circle())
                            }.frame(width: 62, height: 62)
                        }
                        HStack {
                            Text("10K")
                                .foregroundColor(Color.white)
                                .font(Font.custom("Metropolis-Bold", size: 15))
                        }
                        HStack {
                            Text("followers")
                                .foregroundColor(Color.white)
                                .font(Font.custom("Metropolis-Normal", size: 15))
                        }
                    }
                }
            } else {
                //loader
            }
        }.onAppear(perform: initPage)
    }
}

What am I doing wrong? I see that the problem is caused by ScrollView.

2 Answers

Try this one

class NewsState: ObservableObject {

    private let base: String = "api"

    @Published var wagsList: Array<UserSlider> = []

    func getList() {
        let url = NSURL(string: "\(base)/UserApi/getList")
        var mutableURLRequest = URLRequest(url: url! as URL)
        mutableURLRequest.httpMethod = "GET"
        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
        AF.request(mutableURLRequest).responseData { response in
            guard let data = response.data else { return }
            let resp = try! JSONDecoder().decode(Array<UserSlider>.self, from: data)

            let results = resp.map { UserSlider(id: $0.id, uid: $0.uid, image: $0.image) }
            DispatchQueue.main.async {
                self.wagsList = results
            }
        }
    }
}

As it is not clear to me where the error might lay. It could be either in getList or in your View.

This is an easy example of how it works with a Published and ObserverdObject: Note: your getList function is not in this solution as the error could be with your API, JSON ect.

import SwiftUI

struct ContentView: View {

    @ObservedObject var state = NewsState()

    var body: some View {
        Group { //needed for the IF Statement below
            if state.stringList.count > 0 {
                ForEach(self.state.stringList, id: \.self){ s in
                    Text(String(s))
                }
            }
        }.onTapGesture {
            self.state.getNewList()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


class NewsState: ObservableObject {

    @Published var stringList: Array<String> = []

    init() {
        self.getList()
    }

    func getList() {
        self.stringList.append("New")
    }

    func getNewList() {
        self.stringList = []
        self.stringList.append("New new")
    }
}

Related