如何在 URLSession 中调用 completionBlock

How to call completionBlock in URLSession

我正在尝试学习如何使用 Rest API。我想先使用 Github API 从 iPhone 登录。

这是我的模型(还没有完成):

mutating func gettingAceess(completionBlock: @escaping (_ data : Data?, _ response : URLResponse?, _ error : Error?) -> Void ) throws {
    guard username != "", password != "" else {
        throw loginError.emptyUsernameOrPassword
    }

    let loginString = "\(self.username):\(self.password)"
    let resourceUrl = "https://\(loginString)@api.github.com"
    guard let loggingUrl = URL(string: resourceUrl) else {fatalError()}

    let logging = URLSession.shared.dataTask(with: loggingUrl) { (data, response, error) in
        if error != nil {
            print("\(String(describing: error))")
        }
    }

    logging.resume()
}

在控制器中,我希望当用户点击登录按钮时,应该调用获取访问权限的功能。

@IBAction func pressLoginBtn(_ sender: UIButton) {
    if let username = usernameInput.text,  let password = passwordInput.text {
        var logginInformation = LogginReguest(username: username, password: password)
        do {
            try logginInformation.gettingAceess(completionBlock: ...)
        } catch {
  }

try的代码前面,不知道该写什么。谁能帮我?还是我整件事都做错了?

do {
  // if completion block is last argument; you can use trailing syntax
  try logginInformation.gettingAceess() { (data, response, error) in
     // as your completion block have this signature
     // completionBlock: @escaping (_ data : Data?, _ response : URLResponse?, _ error : Error?) -> Void)

  }
} catch {

您还需要更新 gettingAceess 方法。

let logging = URLSession.shared.dataTask(with: loggingUrl) { (data, response, error) in
  if error != nil {
     print("\(String(describing: error))")
   }
   // This line passes this completion block to caller who can read it
   completion(data, response, error)
}

上面的详细信息是如何让完成块在您的示例中工作。建议不要直接传递 URLSession 完成块;而是处理它。

enum NKError: Error {
  case networkError
}

func gettingAceess(completionBlock: @escaping (Result<[String: Any], NKError>) -> Void ) {
  let logging = URLSession.shared.dataTask(with: loggingUrl) { (data, response, error) in
    if error != nil {
      print("\(String(describing: error))")
      completion(.failure(NKError.networkError))
    }

    // Now I can check for status or data
    if let data = data {
      // parse the result and then return
      if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
        completion(.success(json))
      }
    }
  }
}

在这种情况下,我试图将 errorjson 传递给调用者。

你的做法是错误的。首先在调用异步任务之前检查空文本字段。

其次,在完成块 return 中创建包含异步任务的函数 throws 接收数据或错误是不好的做法。

这是一个示例,其中 Result 结构 return 将收到的 Data 作为字符串或错误。

mutating func gettingAccess(completionBlock: @escaping (Result<String,Error>) -> Void)
{
    let loginString = "\(self.username):\(self.password)"
    let resourceUrl = "https://\(loginString)@api.github.com"
    guard let loggingUrl = URL(string: resourceUrl) else {fatalError()}

    let logging = URLSession.shared.dataTask(with: loggingUrl) { (data, _, error) in
        if let error = error {
            completion(.failure(error))
        } else {
            let string = String(data: data!, encoding: .utf8)!
            completion(.success(string))
        }
    }

    logging.resume()
}

@IBAction func pressLoginBtn(_ sender: UIButton) {
    guard usernameInput.hasText, passwordInput.hasText else { 
       // show an alert
       return
    }
    let logginInformation = LogginReguest(username: usernameInput.text!, password: passwordInput.text!)
    logginInformation.gettingAccess { result in
        switch result {
        case .success(let string): print(string)
        case .failure(let error): print(error)

        }
    } 
  }

旁注:

请寻找当代教程。带有参数标签和下划线的语法 (_ data : Data?, _ response : URLResponse?, _ error : Error?) 是 Swift 2 旧语法。