В следующих файлах я пытаюсь использовать данные вызова API в шаблоне типа MVVM для отображения данных в моем представлении. Я получаю сообщение об ошибке при попытке создать представление списка. Я пробовал использовать знак доллара «$» в ссылке на viewModel и в ссылке на массив, но ни один из них не работает. Я просмотрел бесчисленное количество видео и прочитал немало руководств по этому вопросу, но ничто не помогло решить мою ошибку. Любая помощь или совет будут очень признательны.
Сообщения об ошибках, которые я получаю: В ReturnsListView, где я пытаюсь использовать список, я получаю 2 сообщения:
Также в ReturnsListView, но в строке, где я пытаюсь получить доступ к «returnItem.productImageUrl», я получаю третье сообщение: 3. «Невозможно преобразовать значение типа «Привязка» в ожидаемый тип аргумента «Строка»»
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
}
}
Затем я настроил эту 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
}
}
}
И, наконец, вот мой 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: {})
}
Что-то еще, что теперь эти ключевые слова async ничего не делают, если в базовом коде есть обработчики завершения.
@lorem ipsum, да, это имеет смысл, если у меня есть обработчик завершения, тогда нет необходимости использовать асинхронность и ожидание. Попробую использовать и то, и другое. Кроме того, я делаю копии этих трех файлов, а затем избавляюсь от всего, кроме простого вызова API и простого текстового поля. Тогда я попробую добавить список обратно. Я дам вам знать, как идут дела.
Вероятно, это опечатка ) на height: imageDimensions. Обратите внимание: использование ObservableObject совершенно допустимо и соответствует рекомендациям Apple. См. официальную ссылку, чтобы узнать, как управлять данными в вашем приложении: Мониторинг данных
@loremipsum, мы начали заново с ReturnsListView и добавляли элементы обратно по одному, но ошибка не вернулась, поэтому, если вы хотите сделать свой комментарий ответом, я отмечу его как решение. Спасибо!





когда вы используете async, вы можете просто удалить ObservableObject и использовать .task, например.
@State var results = ...
...
.task { // task inits in on appear and deinits in disappear (same as StateObject)
results = await ...
}
Итак, вы предлагаете просмотреть файл модели и удалить «: ObservableObject» из строки класса? Это означает, что мне также нужно удалить обертки свойств (at)Published (Xcode загорелся, как фейерверк). Итак, как только ObseravableObject и «(at)Published» будут удалены, как мне получить автоматические обновления моего массива для отображения в Просмотр контента. Я думал, что ObservableObject, «(at)Published», а затем @StateObject работают вместе, чтобы автоматически обновлять.
@StateObject и @Published предназначены только для случаев, когда вам нужна ссылочная семантика для состояния. Поскольку новый .task предоставляет ссылочную семантику, вы можете просто использовать @State.
Эти ошибки чаще всего вызваны опечаткой.
Если вы закомментируете разделы своего кода, вы обнаружите конкретную проблему.
Короткие очень конкретные представления и уменьшение необходимости проверки типов помогают получить более конкретные ошибки.
Где-то опечатка, упростите Views и вы ее найдете. Комментируйте разделы