【问题标题】:Swift 3, URLSession dataTask completionHandler not calledSwift 3,未调用 URLSession 数据任务完成处理程序
【发布时间】:2016-08-20 11:27:19
【问题描述】:

我正在编写一个库,所以不使用 UIKit,即使在我的 iOS 应用程序中,相同的代码也可以工作,但是当我在命令行中执行时不会。在 PlayGround 中,它似乎也可以工作。

由于某种原因回调没有被触发,所以打印语句没有执行。

internal class func post(request: URLRequest, responseCallback: @escaping (Bool, AnyObject?) -> ()) {
    execTask(request: request, taskCallback: { (status, resp)  -> Void in
            responseCallback(status, resp)
    })
}

internal class func clientURLRequest(url: URL, path: String, method: RequestMethod.RawValue,  params: Dictionary<String, Any>? = nil) -> URLRequest {
    var request = URLRequest(url: url)
    request.httpMethod = method
    do {
        let jsonData = try JSONSerialization.data(withJSONObject: (params! as [String : Any]), options: .prettyPrinted)

        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
        request.httpBody = jsonData
    } catch let error as NSError {
        print(error)
    }
    return request
}

private class func execTask(request: URLRequest, taskCallback: @escaping (Bool,
    AnyObject?) -> ()) {

    let session = URLSession(configuration: URLSessionConfiguration.default)
    print("THIS LINE IS PRINTED")
    let task = session.dataTask(with: request, completionHandler: {(data, response, error) -> Void in
        if let data = data {
            print("THIS ONE IS NOT PRINTED")
            let json = try? JSONSerialization.jsonObject(with: data, options: [])
            if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
                taskCallback(true, json as AnyObject?)
            } else {
                taskCallback(false, json as AnyObject?)
            }
        }
    })
    task.resume()
}

Edits -:我正在编写一个库,所以不使用 UIKit,即使在我的 iOS 应用程序中,相同的代码也可以工作,但是当我在命令行中执行时不会。在 PlayGround 中,它似乎也可以工作。

【问题讨论】:

  • 但是如果Both print statements in below code is not executing 那么这与回调无关......只是你的dataTask 方法永远不会被调用。
  • 请告诉我们你如何调用你的dataTask私有方法。
  • 从另一种方法调用它。变量任务正在创建,然后到达 resume()。但completionHandler 没有执行。添加其他有问题的代码。
  • 我现在添加了有问题的整个代码,改变了你建议的方式。还是行不通。仅供参考,我正在使用 xcode-beta-6 "session.dataTask(with: request, completionHandler: {(data, response, error) -> Void in"
  • 好的,我会在你建议的重构后一分钟内编辑这篇文章。

标签: nsurlsession swift3


【解决方案1】:

我从头开始制作了一个简单的应用程序。 (Xcode 8 beta 6 / swift 3) 在控制器中,我粘贴了您的代码。 (加上网址创建..) 我在调试器中看到了所有内容:

这个是打印出来的

这个也是印刷的

我回来了

所以它似乎工作。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let URLString = "https://apple.com"
        let url = URL(string: URLString)
        let request = URLRequest(url: url!)


        ViewController.execTask(request: request) { (ok, obj) in

            print("I AM BACK")

        }

    }

    private class func execTask(request: URLRequest, taskCallback: @escaping (Bool,
        AnyObject?) -> ()) {

        let session = URLSession(configuration: URLSessionConfiguration.default)
        print("THIS LINE IS PRINTED")
        let task = session.dataTask(with: request, completionHandler: {(data, response, error) -> Void in
            if let data = data {
                print("THIS ONE IS PRINTED, TOO")
                let json = try? JSONSerialization.jsonObject(with: data, options: [])
                if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
                    taskCallback(true, json as AnyObject?)
                } else {
                    taskCallback(false, json as AnyObject?)
                }
            }
        })
        task.resume()
    }

}

【讨论】:

  • 我正在编写一个命令行实用程序,所以不使用 UIKit,即使在我的应用程序中相同的代码也可以,但是当我在命令行中执行时不会。在 PlayGround 中,它似乎也可以工作。
【解决方案2】:

我知道答案迟了,但如果你还没有弄清楚问题或在其他地方遇到问题,让我们试试这个。

您需要将会话变量保存在方法范围之外(使其成为实例变量)。由于您在函数范围内本地定义了它。它在完成处理程序可以被调用之前被释放,记住完成处理程序不能保留你的会话对象,并且在运行循环执行之后,垃圾收集器将释放你的会话对象。每当我们想从委托或完成处理程序中回调时,我们都需要保留这些对象..

self.session = URLSession(configuration: URLSessionConfiguration.default)

【讨论】:

    【解决方案3】:

    这里建议的更改是否进行了,现在可以使用了。

    Using NSURLSession from a Swift command line program

    var sema = DispatchSemaphore( value: 0 )
    
    private func execTask(request: URLRequest, taskCallback: @escaping (Bool,
        AnyObject?) -> ()) {
    
        let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil )
    
        session.dataTask(with: request) {(data, response, error) -> Void in
            if let data = data {
                let json = try? JSONSerialization.jsonObject(with: data, options: [])
                if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
                    taskCallback(true, json as AnyObject?)
                } else {
                    taskCallback(false, json as AnyObject?)
                }
            }
        }.resume()
        sema.wait()
    }
    

    【讨论】:

    • taskCallBacks 的解释非常好。
    【解决方案4】:
    let dataTask = session.dataTask(with: request, completionHandler: {data, response,error -> Void in 
        print("Request : \(response)")
    
        let res = response as! HTTPURLResponse
    
        print("Status Code : \(res.statusCode)")
    
        let strResponse = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
        print("Response String :\(strResponse)")
        })
    dataTask.resume()
    

    【讨论】:

      【解决方案5】:

      斯威夫特 3.0

      只需将以下代码复制到您的视图控制器中即可。

      @IBAction func btnNewApplicationPressed (_ sender: UIButton) {
              callWebService()
      }
      
      func callWebService() {
          // Show MBProgressHUD Here
          var config                              :URLSessionConfiguration!
          var urlSession                          :URLSession!
          
          config = URLSessionConfiguration.default
          urlSession = URLSession(configuration: config)
          
          // MARK:- HeaderField
          let HTTPHeaderField_ContentType         = "Content-Type"
          
          // MARK:- ContentType
          let ContentType_ApplicationJson         = "application/json"
          
          //MARK: HTTPMethod
          let HTTPMethod_Get                      = "GET"
          
          let callURL = URL.init(string: "https://itunes.apple.com/in/rss/newapplications/limit=10/json")
          
          var request = URLRequest.init(url: callURL!)
          
          request.timeoutInterval = 60.0 // TimeoutInterval in Second
          request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
          request.addValue(ContentType_ApplicationJson, forHTTPHeaderField: HTTPHeaderField_ContentType)
          request.httpMethod = HTTPMethod_Get
          
          let dataTask = urlSession.dataTask(with: request) { (data,response,error) in
              if error != nil{
                  return
              }
              do {
                  let resultJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
                  print("Result",resultJson!)
              } catch {
                  print("Error -> \(error)")
              }
          }
          
          dataTask.resume()
      }
      

      【讨论】:

      • 考虑解释你的答案。不鼓励仅使用代码的答案。
      • 试过这个答案,没用stackoverflow.com/questions/42481033/…
      • 首先任务不在主线程中。因此,UI 中的任何内容都需要调用 DispatchQueue.main.async(execute:{code}),其次您需要添加回调,否则调用将立即返回。这是为 Swift 3 准备的。
      【解决方案6】:

      有时,对我来说,在这些情况下未调用 completionHandler 的解决方案是因为 Info.plist 上的“允许任意加载”标志被定义为 NO。

      Allow Arbitrary loads flag defined as YES

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-23
        • 1970-01-01
        相关资源
        最近更新 更多