【问题标题】:Swift - How to assign URLSession.dataTask(with:) decoded data to an external variable?Swift - 如何将 URLSession.dataTask(with:) 解码数据分配给外部变量?
【发布时间】:2020-08-22 06:08:46
【问题描述】:

我正在探索 API 并练习使用简单的股票代码检索应用程序。我可以使用自定义查询 URL 成功提取 JSON 数据。我已经正确设置了对象模型:

    struct TCKR: Decodable {
        let symbol: String
        let delayedPrice: Double?
        let iexRealtimePrice: Double
        ...
    }

我还有一个 API 请求处理程序结构,用于处理股票代码字符串、API 令牌和 URL 生成

    struct IEXCloudRequest {
        var tckr: TCKR! //I swear I'll provide it at some point 

        let strTckr: String
        let myToken = "?token=lqj34poiruadosfnp39u2rkndaslkfnmxnip32ur"

        var reqURL: URL {
            return URL(string: "blah" + strTckr + myToken)!
        }
    }

我在 SwiftUI 中,想使用我的 API 请求处理程序创建的 tckr 对象来显示属性。这就是我想要处理对象模型的方式。

    //ContentView.swift

    struct ContentView: View {
        let tckr: TCKR = IEXCloudRequest("AAPL").tckr

        var body: some View {
            Text(tckr.symbol)
        }
    }

问题是我不知道如何从 JSONDecoder 中提取解码的 tckr 并在全局范围内使用它。我目前使用的方法是:

    let task = URLSession.shared.dataTask(with: self.reqURL { data, response, error in
        if let data = data {
            do {
                let tckrShell = try JSONDecoder().decode(TCKR.self, from: data)
                print("object creation success for ticker: \(String(describing: tckrShell!.symbol))")
                //I consistently print from this block so my API Calls and data decoding are working
            } catch {
                print("we have an E")
                print(error)

            }
        } else {
            print("data from URL returned nil")

        }
    }

    task.resume()

每当我尝试在外部分配 tckrShell 变量时,我都会收到一个错误,提示我在使用 @escaping 完成处理程序时无法分配变异的 self 变量,因此无法在全局范围内使用我的 TCKR 对象'。请 Swift 的诸神,帮助兄弟。

【问题讨论】:

    标签: json swift swiftui urlsession


    【解决方案1】:

    要将tckrShell 分配给外部变量,您需要在获取请求方法中使用完成块。你可以这样处理:

    fund doNetworkCall(Your input, completionBlock: @escaping (TCKR) -> Void)  {
       let task = URLSession.shared.dataTask(with: self.reqURL { data, response, error in
            if let data = data {
                do {
                    let tckrShell = try JSONDecoder().decode(TCKR.self, from: data)
                    completionBlock(tckShell)
                    return
                    print("object creation success for ticker: \(String(describing: tckrShell!.symbol))")
                    //I consistently print from this block so my API Calls and data decoding are working
                } catch {
                    print("we have an E")
                    print(error)
                    return
                }
            } else {
                print("data from URL returned nil")
    
            }
        }
    
        task.resume()
    }
    

    【讨论】:

      【解决方案2】:

      您的设置有误。您不能从闭包中更改严格的属性。如果您需要这样做,请使用类而不是结构

      将您的代码重构为 MVVM:

          struct ContentView: View {
      
          @ObservedObject var viewModel: ContentViewModel
      
          var body: some View {
              Text("\(viewModel.ticker?.delayedPrice ?? 0.0)")
          }
      }
      
      class ContentViewModel: ObservableObject {
      
          var ticker: TCKR? = nil {
              didSet {
                  objectWillChange.send()
              }
          }
          var apiService: ApiService?
      
          init(apiService: ApiService = ApiService()) {
              self.apiService = apiService
              getApiCount()
          }
      
          var objectWillChange: ObservableObjectPublisher = ObservableObjectPublisher()
      
          func getApiCount() {
              apiService?.getTheList(completion: { [weak self] (result) in
                  switch result {
                  case .success(let response):
                      DispatchQueue.main.async {
                          self?.ticker = response
                      }
                  case .failure(let error):
                      print(error.localizedDescription)
                  }
              })
          }
      }
      
      
      
      struct TCKR: Decodable {
          let symbol: String
          let delayedPrice: Double?
          let iexRealtimePrice: Double
      
      }
      
      struct IEXCloudRequest {
      
          let strTckr: String
          let myToken = "?token=lqj34poiruadosfnp39u2rkndaslkfnmxnip32ur"
      
          var reqURL: URL {
              return URL(string: "blah" + strTckr + myToken)!
          }
      }
      
      struct ApiService {
      
          let session = URLSession.shared
          let request: IEXCloudRequest
      
          init(request: IEXCloudRequest = IEXCloudRequest(strTckr: "AAPL")) {
              self.request = request
          }
      
          func getTheList(completion: @escaping (Result<TCKR, Error>) -> Void) {
      
              let dataTask = session.dataTask(with: request.reqURL) { (data, response, error) in
      
                  guard let responseData = data else {
                      return
                  }
                  let jsonDecoder = JSONDecoder()
                  do {
                  let response = try jsonDecoder.decode(TCKR.self, from: responseData)
                      completion(.success(response))
                  } catch {
                      print(error)
                      completion(.failure(error))
                  }
              }
              dataTask.resume()
          }
      
      }
      
      
      enum Result<T, E: Error> {
          case success(T)
          case failure(E)
      }
      

      【讨论】:

      • 您需要将 Combine 导入到您的视图模型和视图文件中
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多