NSURLSession在第一次调用中不返回数据 [英] NSURLSession doesn't return data in first call

查看:63
本文介绍了NSURLSession在第一次调用中不返回数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,有必要为网络实现一个类.这是一个将使用URL并提供数据的类.所有这些都是为了不给额外的逻辑控制器打分.我遇到了这样一个问题,当您第一次创建View时,数据不会出现.那是网络课程:

In general, it is necessary to implement a class for the network. This is a class that will take a URL, and to give data. All this is done in order not to score an extra logic controllers. I encountered such a problem that when you first create a View, the data do not come. That's Network Class:

private static var dataTask: NSURLSessionDataTask?

private static var dataJSON: NSData?

private static var sessionConfig: NSURLSessionConfiguration = {
    var configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
    configuration.allowsCellularAccess = false
    configuration.HTTPMaximumConnectionsPerHost = 2
    configuration.HTTPAdditionalHeaders = ["Accept": "application/json"]
    configuration.timeoutIntervalForRequest = 30.0
    configuration.timeoutIntervalForResource = 60.0
    return configuration
}()


static func getListObjectsBy(url: String?) -> NSData? {
    let session = NSURLSession(configuration: sessionConfig)
    log.debug("DataTask start")
    dataTask = session.dataTaskWithURL(NSURL(string: url!)!) { (data, response, error) in
        log.debug("if error = error")
        if let error = error {
            print(error.localizedDescription)
        } else if let httpResponse = response as? NSHTTPURLResponse {
            log.debug("if httpResponse")
            if httpResponse.statusCode == 200 {
                dataJSON = data
            } else {
                print("Bad request")
            }
        }
    }
    dataTask?.resume()
    log.debug("DataTask Resume")
    return dataJSON
}

主控制器中的viewDidLoad方法:

Method viewDidLoad in my main controller:

let response = Network.getListObjectsBy("http://lb.rmc.su/api-dev/v2/wc/5")
print(String(response))

我的日志说我,该数据返回nil.注意,我正在使用SWRevealViewController帮助在控制器之间进行切换.重新加载主视图控制器时,将返回数据.我该怎么办?

My log say me, that data return nil. Notes, i'm switch between controllers with help SWRevealViewController. When reloading the main view controller, the data is returned. What me do?

在此处输入图片描述

推荐答案

您似乎误解了这是一个异步调用.

You seem to be misunderstanding that this is an asynchronous call.

static func getListObjectsBy(url: String?) -> NSData? {
    let session = NSURLSession(configuration: sessionConfig)
    log.debug("DataTask start")
    dataTask = session.dataTaskWithURL(NSURL(string: url!)!) { (data, response, error) in
        // Everything in this block is happening on a separate thread.
        log.debug("if error = error")
        if let error = error {
            print(error.localizedDescription)
        } else if let httpResponse = response as? NSHTTPURLResponse {
            log.debug("if httpResponse")
            if httpResponse.statusCode == 200 {
                // this won't happen until the data comes back from the remote call.
                dataJSON = data
            } else {
                print("Bad request")
            }
        }
    }
    // This code here does not wait for the response from the remote.
    // The call to the remote is sent then this code 
    // is immediately executed WITHOUT WAITING
    dataTask?.resume()
    log.debug("DataTask Resume")
    // dataJSON will be nil until the remote answers.
    return dataJSON
}

执行此操作时:

let response = Network.getListObjectsBy("http://lb.rmc.su/api-dev/v2/wc/5")
print(String(response))

遥控器尚未应答,因此您将得到零分.

The remote has not answered yet so you will get nil.

您的下一个问题可能是对此我该怎么办?".如果不知道自己在做什么,答案是不清楚的.

Your next question might be "what do I do about this?". The answer isn't clear without knowing everything else that you are doing.

线程

多个执行线程就像两个程序同时运行.假设有两个人同时从事两个不同的任务.为了保持界面的响应速度,iOS使用一个执行线程来更新屏幕.如果某个过程必须花费很长时间才能运行,我们不希望屏幕等待完成.假设您必须从某个远程系统中获取数据,并且该远程系统运行缓慢,您的设备将冻结在那里,直到响应返回为止.为了避免这种情况,在另一个线程中完成了诸如调用远程系统之类的活动.该请求将发送到操作系统本身,并在完成操作后告知操作系统回叫.

Multiple threads of execution is like two programs running at the same time. Think of 2 people working on two different tasks at the same time. In order to keep the interface very responsive, iOS uses one thread of execution for updating the screen. If a process has to run that take a long time, we would not want the screen to wait until that is done. Let's say you have to fetch data from some remote system and that remote system is slow, your device would sit there frozen until the response came back. To avoid this, activities like calls to remote systems are done in another thread. The request is sent to the operating system itself and the operating system is told to call back when the operation is done.

这就是这里发生的事情.
设置发送到操作系统的请求.

This is what is happening here.
Sets up the request to send to the operating system.

dataTask = session.dataTaskWithURL(NSURL(string: url!)!)

告诉操作系统开始执行工作.

Tells the operating system to start doing the work.

dataTask?.resume()

此块是回调(也称为闭包).远程调用完成后,iOS将运行此代码.

This block is the callback AKA the closure. iOS will run this code when the remote call is done.

dataTask = session.dataTaskWithURL(NSURL(string: url!)!) { 
    // Closure starts here
    // Gets called when the remote has sent a response.
    (data, response, error) in
    // Everything in this block is happening on a separate thread.
    log.debug("if error = error")
    etc
}

这意味着您必须等到响应返回后才能打印输出.您可以在函数中使用闭包来完成此操作.

This means you must wait until the response has come back before printing your output. You can use a closure in your function to do this.

public typealias CompletionHandler = (data: NSData?, error: NSError?) -> Void

static func getListObjectsBy(url: String?, completion: CompletionHandler) {
    let session = NSURLSession(configuration: sessionConfig)
    log.debug("DataTask start")
    dataTask = session.dataTaskWithURL(NSURL(string: url!)!) { 
        (data, response, error) in
        // Everything in this block is happening on a separate thread.
        log.debug("if error = error")
        if let error = error {
            print(error.localizedDescription)
        } else if let httpResponse = response as? NSHTTPURLResponse {
            log.debug("if httpResponse")
            if httpResponse.statusCode == 200 {
                // this won't happen until the data comes back from the remote call.
            } else {
                print("Bad request")
            }
        }
        // Call your closure
        completion(data, error)
    }
    // This code here does not wait for the response from the remote.
    // The call to the remote is sent then this code 
    // is immediately executed WITHOUT WAITING
    dataTask?.resume()
    log.debug("DataTask Resume")
}

在您的呼叫代码中,您将执行以下操作:

In your calling code you would do this:

Network.getListObjectsBy("http://lb.rmc.su/api-dev/v2/wc/5") {
    (data, error)  in
    if let data == data {
        print(data)
    }
}

这篇关于NSURLSession在第一次调用中不返回数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆