В принятом ответе много запаха кода, и я считаю необходимым его прояснить, прежде чем это загрязнение распространится на разработку SwiftUI.
- Модель вложенных представлений никоим образом не должна поощряться.
Модель представления неоднозначна (почему в ней разрешены логические c / побочные эффекты?)
Модель вложенного представления? Что это хотя бы значит? И снова ничто не мешает вам спрятать в нем побочные эффекты, которые сложнее отследить и отладить. цикл, выпуск).
например; init(placemarkViewModel: PlacemarkViewModel) { self.placemarkViewModel = placemarkViewModel }
Аргумент, который я видел относительно модели вложенного представления, состоит в том, что «это обычная практика».
Нет, это частая ошибка. Что вы чувствуете, когда кто-то это пишет?
`vm1.vm2.vm3.modelY.property1.vm.p2`
Потому что это именно то, что произойдет, если вы будете поощрять это.
- сетевой вызов с побочным эффектом в init ()
MVVM часто обрабатывает ViewModel похож на безобидный тип значения, когда на самом деле это ссылочный тип, заполненный побочными эффектами Control / business logi c /.
Это один из таких примеров. Когда вы создаете «модель», вы инициируете сетевой запрос с побочным эффектом. Это повредит неосведомленному разработчику, который использует вашу «модель».
- Разделение сети и использование типа значения
Сеть не должна быть единственной причиной, по которой вы создаете модель эталонного типа. У вас может быть выделенный объект сетевой службы и модель типа значения.
Если вы уберете всю сеть из «ViewModel», а оставшаяся «ViewModel» сочтете тривиальной или глупой, то вы на правильном пути.
Вместо двух моделей представления и неявных зависимостей вы должны использовать @EnvironmentObject.
например;
final class SharedState: ObservableObject {
@Published var placemark: Placemark?
// other stuff you want to publish
func updatePlacemark() {
// network call to update placemark and trigger view update
}
}
let state = SharedState()
state.updatePlacemark() // explicit call for networking with side effects
// set as environmentObject, e.g.; ContentView().environmentObject(state)
Ваш SearchAddressView может удалить внешний параметр и напрямую получить доступ к environmentObject.
Таким образом, вы можете удалить все проходящие модели представления:
FilterButtonView(title: LocalizedStringKey(stringLiteral: "location"), systemName: "location.fill") {
SearchAddressView()
}
Подождите, но это делает бесполезными мои причудливые модели просмотра?
Это может быть самый лучший вывод из всего этого. Они тебе не нужны. Они вводят дополнительный уровень сложности, который приносит больше вреда, чем пользы (например, вы застряли).