swift AppStorage变量不会在第一次更新

xzv2uavs  于 12个月前  发布在  Swift
关注(0)|答案(1)|浏览(119)

正如标题中所说,3个@AppStorage变量中有2个在第一次没有更新。所以,当视图被关闭时,我必须重新打开它,然后在第二次关闭时,它们都被更新了。准确地说,第一次只有storedCityName被更新了。
这里的观点:

import SwiftUI

struct SearchView: View {
    @Environment(\.dismiss) private var dismiss
    @EnvironmentObject private var searchManager: SearchManager
    @AppStorage("storedUserLatitude") private var storedUserLatitude: Double?
    @AppStorage("storedUserLongitude") private var storedUserLongitude: Double?
    @AppStorage("storedCityName") private var storedCityName: String?

    var body: some View {
        VStack {
            TextField("", text: $searchManager.search)

            ForEach(searchManager.searchResults, id: \.self) { result in
                HStack {
                    VStack {
                        Text(result.title)
                        Text(result.subtitle)
                    }
                }
                .onTapGesture { update(result.title) }
            }
        }
    }

    private func update(_ city: String) {
        searchManager.searchLocation(city)
        storedUserLatitude = searchManager.userLocation?.coordinate.latitude
        storedUserLongitude = searchManager.userLocation?.coordinate.longitude
        storedCityName = city
        dismiss()
    }
}

字符串
这是经理:

import Foundation
import MapKit
import Combine

class SearchManager: NSObject, ObservableObject, MKLocalSearchCompleterDelegate {
    private let completer = MKLocalSearchCompleter()
    @Published var search = ""
    @Published var searchResults = [MKLocalSearchCompletion]()
    @Published var userLocation: CLLocation?
    private var publisher: AnyCancellable?

    override init() {
        super.init()
        completer.delegate = self
        completer.resultTypes = .address

        publisher = $search
            .receive(on: RunLoop.main)
            .sink(receiveValue: { string in
                self.completer.queryFragment = string
            })
    }

    func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
        searchResults = completer.results
    }

    func searchLocation(_ city: String) {
        let geocoder = CLGeocoder()

        geocoder.geocodeAddressString(city) { placemarks, error in
            guard let placemark = placemarks?.first else { return }
            self.userLocation = placemark.location
        }
    }
}


我真的不明白为什么它在第二次尝试时有效,但在第一次尝试时无效。
我还尝试用DispatchQueue.main.asyncAfter(deadline: .now() + 2) { dismiss() }延迟dismiss,看看@AppStorage变量是否需要时间更新,但它没有改变任何东西。
你知道发生什么事了吗?
谢谢,提前!

yrwegjxp

yrwegjxp1#

这里的真实的问题是,您使用searchManager.searchLocation(city)调用了反向地理编码器,它使用了一个reverse geocoding函数来执行反向地理编码。当您向它传递一个块来设置搜索管理器中的值时,SearchView中的代码并没有等待该信息。
在第二次尝试时,您的SearchManager环境对象有时间使用第一次尝试的地理编码进行更新。
你应该考虑更新searchLocation,以确保它只在地理编码发生后运行update中的后续代码。一种方法是允许它接收一个块:

private func update(_ city: String) {
  searchManager.searchLocation(city) {
    storedUserLatitude = searchManager.userLocation?.coordinate.latitude
    storedUserLongitude = searchManager.userLocation?.coordinate.longitude
    storedCityName = city
    dismiss()
  }
}

// in SearchManager
func searchLocation(_ city: String, onComplete: () -> Void) {
  let geocoder = CLGeocoder()

  geocoder.geocodeAddressString(city) { placemarks, error in
    guard let placemark = placemarks?.first else { return }
    self.userLocation = placemark.location
    onComplete()
  }
}

字符串
还有更简洁的方法,您需要正确地处理错误路径,但希望这能给您正确的想法。

相关问题