使用 swift 中的完成从闭包中提取数据

Extract data from closure using completion in swift

首先,这是我第一次尝试 Swift,所以我不太确定自己在做什么。我正在学习,现在遇到了障碍。

我正在尝试实现一个 WatchOS 应用程序,它将在设定的计时器上调用 API 来跟踪某些加密货币价格的波动。

我已经想出如何进行 API 调用并将 JSON 解析到可以打印数据的点,但我正在努力将其从闭包中取出并且到我的界面。我知道执行此操作的正确方法是使用完成处理程序,但我似乎无法深入了解如何在这种情况下使其工作。

如有任何帮助,我们将不胜感激

import SwiftUI

var refresh = bitcoin()
var btc: String = refresh
var eth: String = "ETH"
var doge: String = "DOGE"


struct ContentView: View {
    
    var body: some View {
        VStack(alignment: .leading ){
            
            Label("\(btc)", image: "eth").padding(.vertical, 10.0)
            Label("\(eth)", image: "eth").padding(.vertical, 10.0)
            Label("\(doge)", image: "doge").padding(.vertical, 10.0)
        
        }
        .scaledToFill()
    }

}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
    
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

struct responseData: Codable{
    
    let data: Response?
}

struct Response: Codable{
    var id: String
    var rank: String
    var symbol: String
    var name: String
    var supply: String
    var maxSupply: String
    var marketCapUsd: String
    var volumeUsd24Hr: String
    var priceUsd: String
    var changePercent24Hr: String
    var vwap24Hr: String
}

    func bitcoin() -> String{

            var result: String = "btc"
            var request = URLRequest(url: URL(string: "https://api.coincap.io/v2/assets/bitcoin")!,timeoutInterval: Double.infinity)
            request.httpMethod = "GET"
            
            
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
          guard let data = data else {
            print(String(describing: error))
            return
          }
            let response = try! JSONDecoder().decode(responseData.self, from: data)
            result = (response.data?.priceUsd)!
            print(result)
        }
        
            task.resume()
        return result
        }
    

有很多方法可以实现你想要的,一种方法是使用“ObservableObject”。尝试这样的事情:

import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class CoinModel: ObservableObject {
    @Published var btcPriceUsd = "not yet available"
    @Published var ethPriceUsd = "not yet available"
    @Published var dogePriceUsd = "not yet available"
}

struct ContentView: View {
    @StateObject var coins = CoinModel()

    var body: some View {
        VStack(alignment: .leading ){
            Label("\(coins.btcPriceUsd)", image: "btc").padding(.vertical, 10.0)
            Label("\(coins.ethPriceUsd)", image: "eth").padding(.vertical, 10.0)
            Label("\(coins.dogePriceUsd)", image: "doge").padding(.vertical, 10.0)
        }
        .scaledToFill()
        .onAppear {
           // bitcoin()
           bitcoin2 { price in
              coins.btcPriceUsd = price
           }
        }
    }
    
    func bitcoin() {
        var request = URLRequest(url: URL(string: "https://api.coincap.io/v2/assets/bitcoin")!,timeoutInterval: Double.infinity)
        request.httpMethod = "GET"
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data else {
                return
            }
            let response = try! JSONDecoder().decode(responseData.self, from: data)
            if let respData = response.data {
                DispatchQueue.main.async {
                    coins.btcPriceUsd = respData.priceUsd
                }
            }
        }
        task.resume()
    }
    
}

编辑:如果你真的想使用完成,那么试试这个:

func bitcoin2(completion: @escaping (String) -> Void) {
    var request = URLRequest(url: URL(string: "https://api.coincap.io/v2/assets/bitcoin")!,timeoutInterval: Double.infinity)
    request.httpMethod = "GET"
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data else {
            return completion("")
        }
        let response = try! JSONDecoder().decode(responseData.self, from: data)
        if let respData = response.data {
            DispatchQueue.main.async {
                completion(respData.priceUsd)
            }
        }
    }
    task.resume()
}