NSURLSession 在第一次调用时没有 return 数据
NSURLSession doesn't return data in first call
总的来说,需要为网络实现一个class。这是一个 class,它将接受一个 URL,并提供数据。所有这一切都是为了不得分额外的逻辑控制器。我遇到过这样的问题,刚创建View的时候,数据不来。那是网络 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:
let response = Network.getListObjectsBy("http://lb.rmc.su/api-dev/v2/wc/5")
print(String(response))
我的日志说我,那个数据return 没有。注意,我在 SWRevealViewController 的帮助下在控制器之间切换。重新加载主视图控制器时,数据被 returned。我做什么?
你好像误会了这是一个异步调用。
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))
遥控器还没有接听所以你会得到零。
您的下一个问题可能是 "what do I do about this?"。如果不了解您正在做的所有其他事情,答案就不清楚了。
线程
多线程执行就像两个程序同时运行运行。想象两个人同时处理两项不同的任务。为了保持界面的快速响应,iOS 使用一个执行线程来更新屏幕。如果一个过程必须 运行 花费很长时间,我们不希望屏幕等到它完成。假设您必须从某个远程系统获取数据,而该远程系统速度很慢,您的设备将停在那里直到响应返回。为避免这种情况,调用远程系统等活动在另一个线程中完成。请求被发送到操作系统本身,并告诉操作系统在操作完成时回调。
这就是这里发生的事情。
设置发送到操作系统的请求。
dataTask = session.dataTaskWithURL(NSURL(string: url!)!)
告诉操作系统开始工作。
dataTask?.resume()
这个块是回调又名闭包。 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)
}
}
总的来说,需要为网络实现一个class。这是一个 class,它将接受一个 URL,并提供数据。所有这一切都是为了不得分额外的逻辑控制器。我遇到过这样的问题,刚创建View的时候,数据不来。那是网络 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:
let response = Network.getListObjectsBy("http://lb.rmc.su/api-dev/v2/wc/5")
print(String(response))
我的日志说我,那个数据return 没有。注意,我在 SWRevealViewController 的帮助下在控制器之间切换。重新加载主视图控制器时,数据被 returned。我做什么?
你好像误会了这是一个异步调用。
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))
遥控器还没有接听所以你会得到零。
您的下一个问题可能是 "what do I do about this?"。如果不了解您正在做的所有其他事情,答案就不清楚了。
线程
多线程执行就像两个程序同时运行运行。想象两个人同时处理两项不同的任务。为了保持界面的快速响应,iOS 使用一个执行线程来更新屏幕。如果一个过程必须 运行 花费很长时间,我们不希望屏幕等到它完成。假设您必须从某个远程系统获取数据,而该远程系统速度很慢,您的设备将停在那里直到响应返回。为避免这种情况,调用远程系统等活动在另一个线程中完成。请求被发送到操作系统本身,并告诉操作系统在操作完成时回调。
这就是这里发生的事情。
设置发送到操作系统的请求。
dataTask = session.dataTaskWithURL(NSURL(string: url!)!)
告诉操作系统开始工作。
dataTask?.resume()
这个块是回调又名闭包。 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)
}
}