Home > front end >  async-await "Type of expression is ambiguous without more context" error - in swiftUI
async-await "Type of expression is ambiguous without more context" error - in swiftUI

Time:11-11

In this line DispatchQueue.main.async I get this error:

Type of expression is ambiguous without more context

import Foundation

class ProductListViewModel: ObservableObject {
    @Published var productList = [Product]()
    let webService = WebService()
    
    func downloadData(url: URL) async {
        
        do {
            let product = try await webService.getData(url: url)
            DispatchQueue.main.async {
                self.productList = product.map(ProductViewModel.init)
            }
        } catch {
            print("error")
        }
    }
}

struct ProductViewModel {
    
    let productModel: Product
    var id: Int {
        productModel.id
    }
    var title: String {
        productModel.title
    }
    var price: Double {
        productModel.price
    }
    var description: String {
        productModel.description
    }
    var category: Category {
        productModel.category
    }
    var imageUrl: String {
        productModel.imageUrl
    }
    var rating: Rating {
        productModel.rating
    }
}

struct WebService {
    
    func getData(url: URL) async throws -> [Product] {
        let (data, _) = try await URLSession.shared.data(from: url)
        let product = try? JSONDecoder().decode([Product].self, from: data)
        return product ?? []
    }
}

CodePudding user response:

The error (which is admittedly nondescriptive and unhelpful here) is because you're trying to set [ProductViewModel] (which is what your map returns) to productList which is of the type [Product].

ProductViewModel doesn't seem to have a purpose here -- it's just an identical wrapper around product. You can change your code inside the do block to this:

let products = try await webService.getData(url: url)
DispatchQueue.main.async {
    self.productList = products
}

To further refactor, you should annotate your ProductListViewModel with @MainActor to ensure its properties get set on the main queue and then you can get rid of the DispatchQueue.main.async call -- the new async/await API doesn't mix well with DispatchQueue and vice versa.

@MainActor class ProductListViewModel: ObservableObject {
    @Published var productList = [Product]()
    let webService = WebService()
    
    func downloadData(url: URL) async {
        do {
            let products = try await webService.getData(url: url)
            self.productList = products
        } catch {
            print("error")
        }
    }
}
  • Related