Исправление
Измените свой ForEach
блок на
ForEach(model.results, id: \.self) { text in
Text(text)
}
Объяснение
Сообщения об ошибках SwiftUI здесь не приносят никакой пользы. Настоящее сообщение об ошибке (которое вы увидите, если измените Text(text)
на Text(text as String)
и удалите $
перед model.results
): «Не удалось вывести общий параметр 'ID'».
Другими словами, чтобы использовать ForEach
, элементы, которые вы повторяете, должны быть однозначно идентифицированы одним из двух способов.
- Если элемент является структурой или классом, вы можете привести его в соответствие с протоколом Identifiable, добавив свойство
var id: Hashable
. В этом случае вам не нужен параметр id
.
- Другой вариант - указать
ForEach
, что использовать в качестве уникального идентификатора, с помощью параметра id
. Обновление. Вы должны гарантировать, что в вашей коллекции нет повторяющихся элементов. Если два элемента имеют одинаковый идентификатор, любые изменения, внесенные в одно представление (например, смещение), произойдут с обоими представлениями.
В этом случае мы выбрали вариант 2 и сказали ForEach
использовать сам элемент String в качестве идентификатора (\.self
). Мы можем это сделать, поскольку String соответствует протоколу Hashable.
А как насчет $
?
Большинство представлений в SwiftUI принимают только состояние вашего приложения и строят свой внешний вид на его основе. В этом примере текстовые представления просто берут информацию, хранящуюся в модели, и отображают ее. Но некоторые представления должны иметь возможность возвращаться и изменять состояние вашего приложения в ответ на пользователя:
- Toggle необходимо обновить значение Bool в ответ на переключение
- Ползунок должен обновить значение Double в ответ на слайд
- TextField необходимо обновить значение String в ответ на ввод
Мы определяем, что должна существовать двусторонняя связь между состоянием приложения и представлением, используя Binding<SomeType>
. Таким образом, Toggle требует, чтобы вы передали ему Binding<Bool>
, Slider требует Binding<Double>
, а TextField требует Binding<String>
.
Именно здесь появляется оболочка свойства @State
(или @Published
внутри @ObservedObject
). Эта оболочка свойства «обертывает» значение, которое она содержит в Binding
(вместе с некоторыми другими вещами, чтобы гарантировать, что SwiftUI знает, что нужно обновлять представления при изменении значения) . Если нам нужно получить значение, мы можем просто сослаться на myVariable
, но если нам нужна привязка, мы можем использовать сокращение $myVariable
.
Итак, в этом случае ваш исходный код содержал ForEach($model.results)
. Другими словами, вы говорили компилятору: «Итерировать Binding<[String]>
», но Binding
не является коллекцией, которую вы можете перебирать. Удаление $
говорит: «Итерировать по этой [String]», а Array - это коллекция, которую вы можете перебирать.
person
John M.
schedule
23.09.2019