Search code examples
swiftswiftuiviewmodel

Pass data in to a ViewModel in Swift


I am fairly new to SwiftUI and developing apps on XCode. I have a good experience of other languages but I am struggling to get my head around a few things.

Basically I have a ViewModel set up as an API to pull notifications from my server as below:

import Foundation
import SwiftUI


class NotificationsAPI: ObservableObject {
    @Published var notifications: [KXNotification] = []

    let userId = [something here]
    
    func fetch() {
        guard let url = URL(string: "xxxxxx.php?id=userId") else {
            return
        }
        
        let task = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in guard let data = data, error == nil else {
                return
        }
            
        //Convert to JSON
            do {
                let notifications = try JSONDecoder().decode([KXNotification].self, from: data)
                DispatchQueue.main.async {
                    self?.notifications = notifications
                }
            } catch {
                print(error)
            }
        }
        
        task.resume()
    }
}
   

On my main view I have the below, but I need to pass the "userId" in to the NotificationsAPI View Model on this view so that it brings through the correct notifications from the server.

import SwiftUI

struct NotificationsView: View {
    @StateObject var viewModel = NotificationsAPI()
    
    var body: some View {
        VStack(alignment: .center, spacing: 16) {
            VStack(alignment: .leading, spacing: 8) {
                HStack(alignment: .bottom, spacing: 0) {
                    Text("Notifications")
                        .font(.poppins(size: 20, weight: .medium))
                    
                    Spacer(minLength: 0)
                    
                    Text("View All")
                        .font(.poppins(size: 15, weight: .medium))
                        .themeForegroundColor(\.gray2)
                        .onTapNavigate(to: AllExercisesView())
                }
                
                Text("Notifications: \(viewModel.notifications.count)")
                    .font(.openSans(size: 12, weight: .regular))
            }
            
            VStack(alignment: .center, spacing: 16) {
                ForEach(viewModel.notifications, id: \.self) { notification in
                    LongCardView(
                        image: .web(link: notification.notificationImage),
                        title: notification.notificationTitle,
                        subTitle: notification.notificationDate,
                        icon: "i_icon"
                    )
                }
            }
            .onAppear {
                viewModel.fetch()
            }
        }
    }
}
        

Thanks in advance.

I have tried a number of methods but struggling to get it to work. Would really appreciate some recommendations.


Solution

  • You have a couple of options here.

    1. You could pass a parameter to the fetch() method. So it will look like func fetch(userId: String(or whatever type you have). You can learn how parameters in functions work in the documentation: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/.

    2. As a second option you could initialize your viewModel with userId. You can read about initialization in the documentation: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/initialization. Or ask chatGPT to add it for you

    The first option is much easier and preferable