0

一般来说,需要为网络实现一个类。这是一个接受 URL 并提供数据的类。所有这些都是为了不给额外的逻辑控制器打分。我遇到这样一个问题,第一次创建View的时候,数据不来。那是网络类:

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:

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

我的日志说我,该数据返回零。注意,我在 SWRevealViewController 的帮助下在控制器之间切换。重新加载主视图控制器时,返回数据。我做什么?

在此处输入图像描述

4

1 回答 1

1

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

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))

遥控器还没有回答,所以你会得到零。

您的下一个问题可能是“我该怎么办?”。如果不知道你在做什么,答案是不清楚的。

线程

多线程执行就像两个程序同时运行。想想两个人同时从事两项不同的任务。为了保持界面响应迅速,iOS 使用一个执行线程来更新屏幕。如果一个进程必须运行很长时间,我们不希望屏幕等到它完成。假设您必须从某个远程系统获取数据并且该远程系统很慢,您的设备将冻结在那里直到响应返回。为了避免这种情况,像调用远程系统这样的活动在另一个线程中完成。该请求被发送到操作系统本身,并告诉操作系统在操作完成时回调。

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

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

告诉操作系统开始工作。

dataTask?.resume()

这个块是回调AKA闭包。远程调用完成后,iOS 将运行此代码。

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
}

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

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")
}

在您的调用代码中,您可以这样做:

Network.getListObjectsBy("http://lb.rmc.su/api-dev/v2/wc/5") {
    (data, error)  in
    if let data == data {
        print(data)
    }
}
于 2016-03-19T17:35:18.177 回答