gpt4 book ai didi

SwiftUI 获取 ViewModel 中另一个 ViewModel 的值

转载 作者:行者123 更新时间:2023-12-03 10:22:08 31 4
gpt4 key购买 nike

我的 View 中有这些过滤器,它们都会更新 FilterViewModel,然后由它负责过滤数据。其中一个 View ,SearchAddressView 需要 PlacemarkViewModel 而不是 FilterViewModel,因为它在用户开始输入时提供地址的下拉列表。那里有很多代码,所以我不想将此代码复制到我的 FilterViewModel

但是,我需要从 PlacemarkViewModelFilterViewModel 读取 @Published var placemark: Placemark。我正在尝试将 PlacemarkViewModel 导入到 FilterViewModel 中,然后使用 didSet { } 来读取它的值,但它不起作用。

所以想法是......当用户搜索地址时,这会更新 PlacemarkViewModel 但 FilterViewModel 也需要获取此值。关于如何实现这一点的任何想法?

struct FiltersView: View {
@ObservedObject var filterViewModel: FilterViewModel

var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
FilterButtonView(title: LocalizedStringKey(stringLiteral: "category"), systemName: "square.grid.2x2.fill") {
CategoryFilterView(filterViewModel: self.filterViewModel)
}

FilterButtonView(title: LocalizedStringKey(stringLiteral: "location"), systemName: "location.fill") {
SearchAddressView(placemarkViewModel: self.filterViewModel.placemarkViewModel)
}

FilterButtonView(title: LocalizedStringKey(stringLiteral: "sort"), systemName: "arrow.up.arrow.down") {
SortFilterView(filterViewModel: self.filterViewModel)
}
}
}
}
}

过滤 View 模型

class FilterViewModel: ObservableObject, LoadProtocol {
@Published var placemarkViewModel: PlacemarkViewModel() {
didSet {
print("ok") // nothing
}
}
}

地标 View 模型

class PlacemarkViewModel: ObservableObject {
let localSearchCompleterService = LocalSearchCompleterService()
let locationManagerService = LocationManagerService()
@Published var addresses: [String] = []

// I need this value in my FilterViewMode;
@Published var placemark: Placemark? = nil
@Published var query = "" {
didSet {
localSearchCompleterService.autocomplete(queryFragment: query) { (addresses: [String]) in
self.addresses = addresses
}
}
}

init(placemark: Placemark? = nil) {
self.placemark = placemark
}

var address: String {
if let placemark = placemark {
return "\(placemark.postalCode) \(placemark.locality), \(placemark.country)"
}

return ""
}

func setPlacemark(address: String) {
locationManagerService.getLocationFromAddress(addressString: address) { (coordinate, error) in
let location: CLLocation = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
self.locationManagerService.getAddressFromLocation(location: location) { (placemark: CLPlacemark?) in
if let placemark = placemark {
self.placemark = Placemark(placemark: placemark)
self.query = placemark.name ?? ""
}
}
}
}

func getAddressFromLocation() {
locationManagerService.getLocation { (location: CLLocation) in
self.locationManagerService.getAddressFromLocation(location: location) { (placemark: CLPlacemark?) in
if let placemark = placemark {
self.placemark = Placemark(placemark: placemark)
self.query = placemark.name ?? ""
}
}
}
}
}

最佳答案

接受的答案有很多代码味道,我觉得有必要在这种污染蔓延到 SwiftUI 开发之前澄清它。

  • 不应以任何方式鼓励嵌套 View 模型。

View 模型本身是模棱两可的(为什么它允许控制逻辑/副作用?)

嵌套 View 模型?那有什么意思?再一次,没有什么能阻止你在其中隐藏副作用,更难跟踪和调试。

您还需要考虑维护对象生命周期(初始化、传递嵌套、保留周期、释放)的成本。

例如; init(placemarkViewModel: PlacemarkViewModel) { self.placemarkViewModel = placemarkViewModel }

我看到的关于嵌套 View 模型的论点是“这是一种常见的做法”。

不,这是一个常见的错误。当有人写这篇文章时,你感觉如何?

`vm1.vm2.vm3.modelY.property1.vm.p2`

因为这正是你鼓励这样做时会发生的事情。

  • 在 init() 中有副作用的网络调用

MVVM 通常将 ViewModel 视为一种无害的值类型,而实际上它是一个充满控制/业务逻辑/副作用的引用类型。

这是一个这样的例子。当你创建一个“模型”时,你发起了一个有副作用的网络请求。这会伤害使用您的“模型”的不知情的开发人员。

  • 解耦网络和使用值(value)类型

网络不应该是您制作引用类型模型的唯一原因。您可以拥有专用的网络服务对象和值类型模型。

如果您从“ViewModel”中剥离所有网络,并且发现剩余的“ViewModel”微不足道或愚蠢,那么您就在正确的轨道上。

您应该使用 @EnvironmentObject,而不是拥有两个 View 模型并具有隐式依赖关系。 .

例如;

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。

所以你可以删除所有传递的 View 模型:

FilterButtonView(title: LocalizedStringKey(stringLiteral: "location"), systemName: "location.fill") {
SearchAddressView()
}

等等,但这会让我花哨的 View 模型毫无用处?

这可能是所有这一切中最大的收获。你不需要它们。它们引入了一层额外的复杂性,弊大于利(例如,您被卡住了)。

关于SwiftUI 获取 ViewModel 中另一个 ViewModel 的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61666535/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com