Home > Net >  SwiftUI: Cannot convert value of type 'String' to expected argument type 'Model'
SwiftUI: Cannot convert value of type 'String' to expected argument type 'Model'

Time:06-23

I'm still new to SwiftUI and hope I will be able to explain my problem well.

I followed a tutorial on reading, writing, and deleting data from the Firestore Database in SwiftUI and it all worked. In the tutorial, there is only 1 view used, but I wanted to take it a step further and use further views:

  • List View (to show all items)
  • Form View (form with fields and function to add items)
  • Detail View (shows details of each item and function to delete item)

While I can add new items to my database through Form View and they also show up after going back to List View, when I try to implement the function to delete items in Detail View, XCode throws the error: Cannot convert value of type 'String' to expected argument type 'Model'

I understand I am not using the right parameter in my function, but failing to understand what the right one here is.

Model

import Foundation

struct Model: Identifiable {
 
    var id: String
    var name: String
    var itemName: String
    
}

ItemListModel

import Foundation
import FirebaseCore
import FirebaseFirestore

class ItemListModel: ObservableObject {
    
    @Published var list = [Model]()
    @Published var name = [Model]()
    
    …
    
    func deleteItem(itemDelete: Model) {
        
        // Get a reference to the database
        let database = Firestore.firestore()
        
        // Specifiy the document to delete. Data passed through the method.
        database.collection("xxx").document(itemDelete.id).delete { error in
            
            // Check for errors
            if error == nil {
                // No errors
                
                // Update the UI from the main thread
                DispatchQueue.main.async {
                    
                    // Remove the item that was just deleted
                    self.list.removeAll { items in
                        
                        // Check for the item to remove
                        return items.id == itemDelete.id
                    }
                }
            }
        }
    }

    …
    
}

ItemList
My thinking was to include an ID to tell the function what to delete exactly, so I included it in this file and pass it to the Detail View. Not sure if I need to pass the ID at this point though.

import SwiftUI

struct ItemList: View {
    
    @EnvironmentObject var model: ItemListModel
    
    @State var name = ""
    @State var itemName = ""
    @State var itemId = ""
    
    var body: some View {

        …

        ForEach(model.list) { item in

            NavigationLink(destination: Detail(name: item.name, itemName: item.itemName, itemId: item.id)) {
                HStack {
                    Text(item.name)
                    Text(item.itemName)
                }
            }
        }
    }
}

Detail And this is the view where XCode throws the error message Cannot convert value of type 'String' to expected argument type 'Model'.

import SwiftUI

struct Detail: View {
    
    @EnvironmentObject var model: ItemListModel
    
    var name: String
    var itemName: String
    var itemId: String
    
    var body: some View {
        
        VStack {
                
            Text(name)
            Text(itemName)

            Button {
                // delete (hopefully) the current item
                model.deleteItem(itemDelete: itemId) // XCode throws error Cannot convert value of type 'String' to expected argument type 'Model'.
            } label: {
                Text("Delete")
            }

            …

        }
    }
}

Thank you for reading through all of this and I truly hope someone can help me and my confused brain here!

CodePudding user response:

The expected type is Model. -> deleteItem(itemDelete: Model)

The easy solution is to pass a Model instance rather than the three strings

struct Detail: View {
    
    @EnvironmentObject var model: ItemListModel
    
    let item: Model
   
    var body: some View {
        
        VStack {
                
            Text(item.name)
            Text(item.itemName)
            Button {
                model.deleteItem(itemDelete: item) 
            } label: {
                Text("Delete")
            }
            …
        }
    }
}

and in ItemList replace

NavigationLink(destination: Detail(name: item.name, itemName: item.itemName, itemId: item.id)) {

with

NavigationLink(destination: Detail(item: item)) {
  • Related