Asynchronous 使用Combine和SwiftUI的异步操作
我试图弄清楚如何使用Combine和SwiftUI处理异步操作 例如,我有一个Asynchronous 使用Combine和SwiftUI的异步操作,asynchronous,swiftui,combine,Asynchronous,Swiftui,Combine,我试图弄清楚如何使用Combine和SwiftUI处理异步操作 例如,我有一个HealthKitManager类,该类处理健康商店授权请求 final class HealthKitManager { enum Error: Swift.Error { case notAvailable case authorisationError(Swift.Error) } let healthStore = HKHealthStore()
HealthKitManager
类,该类处理健康商店授权请求
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))
}
}
}
}
我想做的是使用Combine,而不是结果
闭包。我猜是这样的
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)
}
}
}
}
我猜@发布的var授权结果:结果?
不正确?
我应该使用Future/Promise
,其他什么吗
更新 我发现还有另一种方式来表示警报
.alert(item: self.$error) { error in
Alert(title: Text(error.localizedDescription))
这意味着我不需要showError
的Bool(它只需要Error
对象是可识别的
)修改了我的答案,使之基于:
扩展结果{
func getFailure()->失败{
切换自身{
案例.失败(let-er):
回程器
违约:
归零
}
}
func绑定(
success successClosure:(@escaping(success)->B),
failureClosure:@escaping(failure)->B)->Binding{
返回绑定(
获取:{
切换自身{
成功案例(let value):
返回successClosure(值)
案例.失败(让失败):
返回故障关闭(故障)
}
},设置:{uin})
}
func implicitBinding(failure-failureClosure:@escaping(failure)->Success)->Binding{
返回绑定(成功:{$0},失败:failureClosure)
}
}
类HealthKitManager:ObservableObject{
枚举错误:Swift.Error{
案例授权错误(Swift.错误)
案例不可用
}
@已发布的var授权结果=结果。失败(.notAvailable)
让healthStore=HKHealthStore()
func getHealthKitData(对象:集合){
guard HKHealthStore.isHealthDataAvailable()其他{
自我授权结果=.failure(.notAvailable)
返回
}
self.healthStore.requestAuthorization(toShare:nil,read:objects){completed,中出错
DispatchQueue.main.async{
如果let error=error{
自我授权结果=.failure(.authorizationError(错误))
返回
}
自我授权结果=.success(已完成)
}
}
}
}
结构ContentView:View{
@ObservedObject变量healthKitManager=healthKitManager()
让objectTypes=Set([HKObjectType.quantityType(forIdentifier:.bloodGlucose)!]))
var body:一些观点{
导航视图{
导航链接(目标:NextView(),
isActive:healthKitManager.AuthorizationResult.implicitBinding(失败:{inFalse})){
按钮(“显示下一个视图”){
self.healthKitManager.getHealthKitData(用于:self.objectTypes)
}
}.navigationBarTitle(“内容视图”)
}.alert(显示为:healthKitManager.authorizationresult.binding(成功:{infalse},失败:{intrue})){
let message=healthKitManager.authorizationresult.getFailure()?.localizedDescription??“
返回警报(标题:Text(“错误”)、消息:Text(消息)、dismissButton:.cancel())//或此
}
}
}
我喜欢有结果
,就像您在第二个变体中所做的那样
@Published var authorisationResult: Result<Bool, Error>?
@已发布的var授权结果:结果?
因此,可能的使用方法如下
NavigationLink(destination: NextView(), isActive:
Binding<Bool>.ifSuccess(self.healthKitManager.authorisationResult)) {
Button("Show Next View") {
self.healthKitManager.getHealthKitData(for: self.objectTypes)
}
}.navigationBarTitle("Content View")
NavigationLink(目的地:NextView(),isActive:
绑定.ifSuccess(self.healthKitManager.authorizationresult)){
按钮(“显示下一个视图”){
self.healthKitManager.getHealthKitData(用于:self.objectTypes)
}
}.navigationBarTitle(“内容视图”)
哪里有方便的分机
extension Binding {
static func ifSuccess<E>(_ result: Result<Bool, E>?) -> Binding<Bool> where E: Error {
Binding<Bool>(
get: {
guard let result = result else { return false }
switch result {
case .success(true):
return true
default:
return false
}
}, set: { _ in })
}
}
扩展绑定{
静态函数ifSuccess(uresult:result?->绑定,其中E:Error{
装订(
获取:{
guard let result=result else{return false}
切换结果{
成功案例(正确):
返回真值
违约:
返回错误
}
},设置:{uin})
}
}
错误的变量
也可以用类似的方法完成。谢谢。这肯定会起作用,但将hasaauthorizationerror
、authorizationError
和isAuthorized
分别设置为不同的值似乎有点不对劲……尤其是当这三个值都包含在单一结果类型中时。这个类也可以用于其他异步操作,因此为每个操作添加3个额外的@Published
变量似乎很多。我希望Combine能有更好的方法来处理这个问题。谢谢你的回答-很遗憾,这需要这么多额外的代码来完成。@AshleyMills,如果苹果为所有事情都提供API,我们会怎么做?我们不是程序员吗?=^)@Published
为您提供发布者,并通过@ObservedObject
动态属性与SwiftUI视图刷新自动集成。你可以使用任何东西,但要考虑利弊。把简单的事情复杂化是目标吗?
@Published var authorisationResult: Result<Bool, Error>?
NavigationLink(destination: NextView(), isActive:
Binding<Bool>.ifSuccess(self.healthKitManager.authorisationResult)) {
Button("Show Next View") {
self.healthKitManager.getHealthKitData(for: self.objectTypes)
}
}.navigationBarTitle("Content View")
extension Binding {
static func ifSuccess<E>(_ result: Result<Bool, E>?) -> Binding<Bool> where E: Error {
Binding<Bool>(
get: {
guard let result = result else { return false }
switch result {
case .success(true):
return true
default:
return false
}
}, set: { _ in })
}
}