如何异步返回视图?什么?

问题描述 投票:0回答:1

我有一个这样的按钮

Button(action: {
  // do something
}, label: {
  Text("The price is \(price)")
})

第一个问题是按钮的标签部分需要一个视图。

此外,价格是使用类似

的方式从应用程序商店异步检索的
func priceFor(_ productID: String,
                onConclusion:GetPriceHanler?) {
   
    inapp?.fetchProduct(productIdentifiers: [productID],
                       handler: { (result) in
      switch result {
      case .success(let products):
        let products = products
        
        guard let product = products.first
        else {
          onConclusion?("")
          return
        }
        
        onConclusion?("\(product.price)")
        
      case .failure(let error):
        print(error.localizedDescription)
        onConclusion?("")
      }
    })
  }

因此,该函数在完成后会运行一个闭包。

我考虑过创建另一个函数,它返回一个视图来调用这个函数......类似

@ViewBuilder
func priceViewFor(_ productID: String) -> some View { }

如果函数返回价格或无效则为空,我没问题,但如果我这样做,我将在一个闭包内结束,从那里我无法返回视图。

类似的东西

@ViewBuilder
func priceViewFor(_ productID: String) -> some View {
  myAppStore.priceFor(productID) { price in
  return Text(price) ?????????????
}

我该如何做到这一点?

swift swiftui closures
1个回答
0
投票

基本思想是有一个

@State
代表价格,无论是否已被获取。在
label:
视图生成器中检查此状态,如果未获取,则显示其他内容。

一个简单的设计是使用可选的:

@State var price: String?
Button {
  // do something
} label: {
    // check if the price has been fetched
    if let price {
        Text("The price is \(price)")
    } else {
        ProgressView("Loading Price...")
    }
}
.disabled(price == nil) // you might want to disable the button before the price has been fetched
.onAppear {
    // set the state in the completion handler
    myAppStore.priceFor(productID) { price in
        self.price = price
    }
}

看到价格获取可能会失败,我建议使用

Result
代替:

@State var price: Result<String, Error>?
switch price {
case .none:
    ProgressView("Loading Price...")
case .failure(let error):
    Label("Failed! (\(error))", systemImage: "xmark")
case .success(let price):
    Text("The price is \(price)")
}

这意味着您需要更改

priceFor
,以便将
Result<String, Error>
传递给
onConclusion
闭包。

此外,请考虑使用 Swift Concurrency API 进行重写。用法如下:

.task {
    do {
        price = .success(try await myAppStore.priceFor(productID))
    } catch {
        price = .failure(error)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.