Home > Software design >  SwiftUI: How to pass arguments to class from view?
SwiftUI: How to pass arguments to class from view?

Time:10-31

I have a class that conforms to ObservableObject, which takes some arguments. When I then use @ObservedObject var someName = className() in my view to access all the functions and data in the class, I get an error saying:

Missing arguments for parameters 'pickedVideo', 'pickedImage', 'retrievedImages', 'retrievedVideos' in call

I am aware that I somehow have to pass the arguments from my view to the class.

But how do I pass variables from my view to my class?

Class:

class DBFunctions : ObservableObject {
    
    init(pickedVideo: [String], pickedImage: [UIImage], retrievedImages: [UIImage], retrievedVideos: [AVPlayer]) {
        self.pickedVideo = pickedVideo
        self.pickedImage = pickedImage
        self.retrievedImages = retrievedImages
        self.retrievedVideos = retrievedVideos
    }
    
    var pickedVideo : [String]
    var pickedImage : [UIImage]
    var retrievedImages : [UIImage]
    var retrievedVideos : [AVPlayer]
    
    func somefunc() {
        
    }
}

View:

struct ContentView: View {
    @ObservedObject var helpFuncs = DBFunctions()

    
    @State var showPicker: Bool = false
    @State var pickedImage: [UIImage] = []
    @State var retrievedImages = [UIImage]()
    @State var player : AVPlayer?
    
    @State var width : CGFloat = 0
    @State var retrievedVideos = [AVPlayer]()
    @State var pickedVideo: [String] = []
    
    @State var isPaused = false

    var body: some View {
        VStack{
            Button(action: {
                helpFuncs.uploadImage()
            }) {
                Text("Upload Image")
            }  
        }
    }

CodePudding user response:

What you are doing is something like an anti-pattern... The ObservableObject should be getting their "truth" from the Model, and not from the view. So, normally speaking, or those values initialize themselves, or you get their from the Model.

To be clear, you should create an object first, from model data, then pass its instance to the View. That's what MVVM is all about.

Fell free to increase your question if something that I answered was not clear enough.

Edit1: If you need to communicate something (like a choice) from the View to the ObservableObject, you should do this via "Intents"... that is normally a func in the ObservableObject class. Those Intents (in my way to architect this is failable), if the Intent goes well, ObservableObject change the Model and Publish their new results to the View, which redraws itself. If the "Intent" not go through, or I launch an Alert (if it's critical) or I simply ignore.

CodePudding user response:

As mentioned, you are not using ObservableObject as it is meant to be used.

Look at this link, it gives you some good examples of how to use ObservableObject and manage data in your app https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app

Try something like this example code:

class DBFunctions : ObservableObject {
    @Published var pickedVideo : [String]  // <-- here  @Published
    @Published var pickedImage : [UIImage]
    @Published var retrievedImages : [UIImage]
    @Published var retrievedVideos : [AVPlayer]
    
    init() {
        self.pickedVideo = []
        self.pickedImage = []
        self.retrievedImages = []
        self.retrievedVideos = []
    }

    func uploadImage() {  }
}

struct ContentView: View {
    @StateObject var helpFuncs = DBFunctions() // <-- here
    
    @State var showPicker: Bool = false
    @State var player : AVPlayer?
    @State var width : CGFloat = 0
    @State var isPaused = false
    
    // do not use these, use the ones in your helpFuncs model directly
    // like: helpFuncs.pickedImage = ...
 //   @State var pickedImage: [UIImage] = []
 //   @State var retrievedImages = [UIImage]()
 //   @State var retrievedVideos = [AVPlayer]()
 //   @State var pickedVideo: [String] = []

    var body: some View {
        VStack{
            Button(action: {
                helpFuncs.uploadImage()
            }) {
                Text("Upload Image")
            }
        }
        .onAppear {
            // here do some initialisation of your helpFuncs, for example
        }
    }
}

With your original code (and question), You can of course pass some initial values, like this:

@ObservedObject var helpFuncs = DBFunctions(pickedVideo: [], pickedImage: [], retrievedImages: [], retrievedVideos: [])

  • Related