我有一个这样的按钮

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) ?????????????
}

以比特的名义,我怎么做到这一点呢?

推荐答案

基本的 idea 是有一个@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并发API进行重写.然后用法如下所示:

.task {
    do {
        price = .success(try await myAppStore.priceFor(productID))
    } catch {
        price = .failure(error)
    }
}

Swift相关问答推荐

是否有一个Kotlin等价的Swift s @ AddendableReport注释'

如何将泛型函数存储到变量中?

如何强制创建新的UIViewControllerRenatable|更新Make UIViewController上的视图

不能将符合协议的SWIFT类的实例分配给需要该协议的Objective-C属性

异步/等待函数的XCTAssertThrowsError

MacOS 13-如何使用SwiftUI创建Message.App设置工具栏?

可以';t在标记为@Observable的类上使用属性包装

从 iPhone 中的安全飞地获取真正的随机数?

并发执行代码中捕获的 var 的变异

如何从数据中读取以空结尾的字符串?

SwiftUI - Select 器没有 Select 值

如何在 SwiftUI 中正确实现Collection 夹?

从 Finder 打开文件时,SwiftUI 的应用程序(_ openFile:) 从未调用过

如何在 SwiftUI 中通过按钮点击一次为一个更改设置动画?

如何使被拖动的对象成为前景(foreground)对象

仅在 Swift 中创建 Setter

调整文本的字体大小以适应 UIButton

在 Swift 中指定 UITextField 的边框半径

如何使用 Swift 枚举作为字典键? (符合 Equatable)

显示 UIAlertController 的简单 App Delegate 方法(在 Swift 中)