In the following files where I am attempting to use the data from an API call in a MVVM type pattern to display the data in my view. I am getting an error on the view when I try to create a List view. I have tried using a dollar sign "$" on the reference to the viewModel and on the reference to the array, but neither is working. I've watched countless videos and read quite a few tutorials on this, but nothing is solving my error. Any help or advice would be greatly appreciated.
The error messages I am getting are: In ReturnsListView where I try to use a List, I get 2 messages:
Also in ReturnsListView, but on the line where I try to access "returnItem.productImageUrl" I get the third message: 3. "Cannot convert value of type 'Binding' to expected argument type 'String'"
import Foundation
struct ReturnItem: Codable, Identifiable {
let id = UUID().uuidString
var puNbr: Int
var puLineNbr: Int
var packCd: String
var puQty: Int
var partialReturn: Bool
var itemDescription: String
var itemSize: String
var itemPack: Int
var reasonType: String
var reasonSubtype: String
var invoiceNbr: Int
var productImageUrl: String
var formattedRetailUPC: String
var puStatus: String
var editable: Bool
enum CodingKeys: CodingKey {
case puNbr, puLineNbr, packCd, puQty, partialReturn,
itemDescription, itemSize, itemPack, reasonType, reasonSubtype,
invoiceNbr, productImageUrl, formattedRetailUPC, puStatus, editable
}
}
Then I have set up this ViewModel:
import Foundation
@MainActor
class ReturnsViewModel: ObservableObject {
@Published var returnItemsArray: [ReturnItem] = []
@Published var displayAPIError: Bool = false
@Published var errorText: String = ""
func getDataWithAlamoFire() async {
Service.sharedInstance.returnsApi { returnItems in
self.returnItemsArray = returnItems
} failure: { alertType, errorText in
print("🪵 ReturnsListAPI AlertType is: \(alertType)")
print("‼️ ReturnsListAPI ErrorText is: \(errorText)")
self.displayAPIError = true
self.errorText = errorText
}
}
}
And finally here is my ReturnsListView:
import SwiftUI
struct ReturnsListView: View {
@StateObject var returnsVM = ReturnsViewModel()
@State var partialReturnToggle = false
@State var showAlert = false
var imageDimensions = 96.0
var iPadImageDimentions = 80.0
var iPadTextSize = 15.0
var body: some View {
NavigationView {
VStack(alignment: .center) {
// Getting the first two errors on the line below
// 1. "Cannot convert value of type '[ReturnItem]' to expected argument type
// 'Binding<Data>'"
// and
// 2. "Generic parameter 'Data' could not be inferred"
List(returnsVM.returnItemsArray) { returnItem in
HStack { // main return list row
// Left side of row with Image and Partial Pack Toggle
VStack(alignment: .center) {
if displayImages {
// Getting the following message on the line below:
// "Cannot convert value of type 'Binding<Subject>' to expected argument type 'String'"
Image(uiImage: getReturnsImage(
productImageUrlString: returnItem.productImageUrl,
width: imageDimensions,
height: imageDimensions)
)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: imageDimensions, height: imageDimensions)
}
VStack{
Text("Partial Pack")
Toggle("Partial Pack Toggle", isOn: $partialReturnToggle)
.labelsHidden()
.toggleStyle(SwitchToggleStyle(tint: .orange))
}
}
.padding(.trailing)
// Right side of row with Item details and quantity buttons
VStack(alignment: .center) {
Text(returnItem.itemDescription ?? "") // item description
.fontWeight(.black)
.frame(alignment: .center)
HStack(alignment: .center) {
Spacer()
Text(returnItem.puStatus ?? "") // pickup status
.font(.system(size: 17))
.fontWeight(.bold)
.foregroundColor(.red)
Spacer()
}
HStack {
Text(returnItem.itemSize ?? "") // itemSize
.font(.system(size: 20))
Spacer()
if let itemPack = returnItem.itemPack {
Text("(\(itemPack) pack)") // itemPack
.font(.system(size: 20))
}
}
HStack(alignment: .leading) {
Text(returnItem.formattedRetailUPC ?? "") // formattedRetailUPC
.font(.system(size: 20))
Text(returnItem.invoiceNbr) // invoice number
.font(.system(size: 20))
}
}
}
.listRowBackground(Color(UIColor.tertiarySystemBackground))
}
.listStyle(.plain)
.ignoresSafeArea()
.offset(y: -16)
}
.background((Color(UIColor.tertiarySystemBackground)))
}
.navigationViewStyle(.stack)
.task {
await returnsVM.getDataWithAlamoFire()
} // NaviationView
} // End of Body
}
func getReturnsImage(productImageUrlString: String, width: Double, height: Double) -> UIImage {
if productImageUrlString.endsWith("nulljpg") {
return UIImage(named: "placeHolderImage")!
} else {
let formattedImageUrlString = productImageUrlString.replacingOccurrences(of: " ", with: "%20")
if let productImageUrl = URL.init(string: formattedImageUrlString) {
print("🪵 Formatted ProductImageURL is: \(productImageUrl)")
let frame = CGRect(x: 0, y: 0, width: width, height: height)
let prodUIImageView = UIImageView(frame: frame)
prodUIImageView.af.setImage(withURL: productImageUrl)
return prodUIImageView.image ?? UIImage(named: "placeHolderImage")!
} else {
return UIImage(named: "placeHolderImage")!
}
}
}
#Preview {
ReturnsListView(navHeight: 42, infoString: "Test Customer - 888777", backPressed: {})
}
These errors are more often than not caused by a typo.
If you comment out sections of your code you’ll find the specific issue.
Short very specific views and reducing the need for type checking helps get more specific errors.