Ich versuche herauszufinden, wie man mit asynchronen Operationen mit Combine und SwiftUI arbeitet.
Zum Beispiel habe ich eine HealthKitManager
Klasse, die unter anderem die Beantragung einer Genehmigung für ein Reformhaus behandelt…
final class HealthKitManager {
enum Error: Swift.Error {
case notAvailable
case authorisationError(Swift.Error)
}
let healthStore = HKHealthStore()
func getHealthKitData(for objects: Set<HKObjectType>, completion: @escaping (Result<Bool, Error>) -> Void) {
guard HKHealthStore.isHealthDataAvailable() else {
completion(.failure(.notAvailable))
return
}
self.healthStore.requestAuthorization(toShare: nil, read: objects) { completed, error in
DispatchQueue.main.async {
if let error = error {
completion(.failure(.authorisationError(error)))
}
completion(.success(completed))
}
}
}
}
welches wie folgt verwendet wird…
struct ContentView: View {
let healthKitManager = HealthKitManager()
@State var showNextView = false
@State var showError = false
@State var hkError: Error?
let objectTypes = Set([HKObjectType.quantityType(forIdentifier: .bloodGlucose)!])
var body: some View {
NavigationView {
NavigationLink(destination: NextView(), isActive: $showNextView) {
Button("Show Next View") {
self.getHealthKitData()
}
}.navigationBarTitle("Content View")
}.alert(isPresented: $showError) {
Alert(title: Text("Error"), message: Text(hkError?.localizedDescription ?? ""), dismissButton: .cancel())
}
}
func getHealthKitData() {
self.healthKitManager.getHealthKitData(for: self.objectTypes) { result in
switch result {
case let .success(complete):
self.showNextView = complete
case let .failure(error):
self.hkError = error
self.showError = true
}
}
}
}
Was ich tun möchte, ist Kombinieren anstelle eines Result
Verschlusses. Ich vermute so etwas…
final class HealthKitManager: ObservableObject {
enum Error: Swift.Error {
case notAvailable
case authorisationError(Swift.Error)
}
@Published var authorisationResult: Result<Bool, Error>?
let healthStore = HKHealthStore()
func getHealthKitData(for objects: Set<HKObjectType>) {
guard HKHealthStore.isHealthDataAvailable() else {
self.authorisationResult = .failure(.notAvailable)
return
}
self.healthStore.requestAuthorization(toShare: nil, read: objects) { completed, error in
DispatchQueue.main.async {
if let error = error {
self.authorisationResult = .failure(.authorisationError(error))
return
}
self.authorisationResult = .success(completed)
}
}
}
}
Aber dann ist es unklar, wie man sich an die Werte für NavigationLink(isActive:)
und bindet alert(isPresented:)
und den Fehler erhält.
struct ContentView: View {
@ObservedObject var healthKitManager = HealthKitManager()
let objectTypes = Set([HKObjectType.quantityType(forIdentifier: .bloodGlucose)!])
var body: some View {
NavigationView {
NavigationLink(destination: NextView(), isActive: ????) { // How do I get this
Button("Show Next View") {
self.healthKitManager.getHealthKitData(for: self.objectTypes)
}
}.navigationBarTitle("Content View")
}.alert(isPresented: ????) { // or this
Alert(title: Text("Error"), message: Text(????.localizedDescription ?? ""), dismissButton: .cancel()) // or this
}
}
}
Ich vermute, das @Published var authorisationResult: Result<Bool, Error>?
ist nicht richtig? Soll ich Future / Promise
etwas anderes verwenden?
Aktualisieren
Ich habe festgestellt, dass es eine andere Möglichkeit gibt, eine Warnung anzuzeigen…
.alert(item: self.$error) { error in
Alert(title: Text(error.localizedDescription))
was bedeutet, dass ich den Bool nicht brauche showError
(es muss nur das Error
Objekt sein Identifiable
)
@Published
Bietet Ihnen einen Publisher und verfügt über eine automatische Integration in die Aktualisierung der SwiftUI-Ansicht über@ObservedObject
dynamische Eigenschaften. Sie können alles verwenden, aber über Vor- und Nachteile nachdenken . Ist es das Ziel, einfache Dinge komplex zu machen?