Swift 2 如何在继续代码之前等待 NSURLSessionDataTask 完成
Swift 2 How do I wait for NSURLSessionDataTask to complete before continuing code
在此代码中,request.getStatusCode()
和 request.getIsConnected()
都在 task
块中的代码执行之前执行
即dataTask.resume() 在执行任何后续代码之前不会执行,无论是同一函数 class 中的代码还是单独的 class 中的代码。
我试过将函数调用放在主队列(串行)、全局队列(并发)、手动串行队列、手动并发队列和 NSOperationQueue 中,然后是一个 while 循环等待直到关闭完成。
while isDoingSomething {
NSThread.sleepForTimeInterval(0.0)
}
循环。
我已将所有 GCD 或操作排除在这段代码之外,以避免我尝试过的每个队列场景的混乱。
ViewController.swift
import Cocoa
class ViewController: NSViewController {
.
.
.
func login(username username: String, password: String) {
let url = "https://www.awebsite.com/login"
let URL = NSURL(string: url)
let method = "POST"
let params = "username=\(username)&password=\(password)"
vis = URLVisitor(URL: URL!, params: params, method: method, jsonParams: [:])
vis.execute()
cookies = vis.getCookies()
let contentsOfURL = vis.getContentsOfURL()
}
.
.
.
}
URLVisitor.swift
import Cocoa
let queue = NSOperationQueue
class URLVisitor: NSOperation {
.
.
.
func execute() {
let request = Request(URL: URL!, params: params, method: method, jsonParams: jsonParams)
if !self.cookies.isEmpty {
request._setCookies(self.cookies)
}
request._setAuthorizationHeader(self.authorizationHeader)
request.sendRequest()
self.statusCode = request.getStatusCode()
self.isConnected = request.getIsConnected()
}
.
.
.
}
Request.swift
import Cocoa
class Request: NSOperation {
.
.
.
func sendRequest() {
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: URL)
request.HTTPMethod = method
// send jsonParams or params
if jsonParams.count != 0 {
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonParams, options: .PrettyPrinted)
request.setValue("aplication/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPBody = jsonData
} catch {
}
} else {
request.HTTPBody = self.params.dataUsingEncoding(NSUTF8StringEncoding)
}
let task = session.dataTaskWithRequest(request) {
(data, response, error) in
NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookies(self.cookies, forURL: self.URL, mainDocumentURL: nil)
if data != nil {
self.data = data!
do {
let responseHeaders = response as! NSHTTPURLResponse
self.statusCode = responseHeaders.statusCode
switch self.statusCode {
case 200:
print("200: OK. getting contentsOfURL and cookies")
self.contentsOfURL = try NSString(contentsOfURL: self.URL, encoding: NSUTF8StringEncoding)
self.cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookiesForURL(self.URL)!
case 400:
print("400: page not found on web")
case 404:
print("404: page not found on server")
case 407:
print("407: failed authenticate proxy credentials")
default:
print("unable to get statusCode")
}
} catch {
}
} else {
print("\(self.statusCode): unable to get response ")
}
NSThread.sleepForTimeInterval(1.0)
}
task.resume()
}
正确的方法是添加完成处理程序
func sendRequest(completion: () -> Void) {
// ...
let task = session.dataTaskWithRequest(request) {
// ...
completion()
}
task.resume()
}
用法:
let r = Request()
r.sendRequest {
// It's done, do something
}
如果你非要阻塞线程(希望不是主线程),使用信号量。但是请记住,无论请求成功还是失败,都要向信号量发出信号。我见过太多在请求失败时忘记发出信号量的代码,因此应用程序挂断了。
func sendRequest() {
let semaphore = dispatch_semaphore_create(0)
let task = session.dataTaskWithRequest(request) {
// ...
dispatch_semaphore_signal(semaphore)
}
task.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}
在此代码中,request.getStatusCode()
和 request.getIsConnected()
都在 task
块中的代码执行之前执行
即dataTask.resume() 在执行任何后续代码之前不会执行,无论是同一函数 class 中的代码还是单独的 class 中的代码。
我试过将函数调用放在主队列(串行)、全局队列(并发)、手动串行队列、手动并发队列和 NSOperationQueue 中,然后是一个 while 循环等待直到关闭完成。
while isDoingSomething {
NSThread.sleepForTimeInterval(0.0)
}
循环。
我已将所有 GCD 或操作排除在这段代码之外,以避免我尝试过的每个队列场景的混乱。
ViewController.swift
import Cocoa
class ViewController: NSViewController {
.
.
.
func login(username username: String, password: String) {
let url = "https://www.awebsite.com/login"
let URL = NSURL(string: url)
let method = "POST"
let params = "username=\(username)&password=\(password)"
vis = URLVisitor(URL: URL!, params: params, method: method, jsonParams: [:])
vis.execute()
cookies = vis.getCookies()
let contentsOfURL = vis.getContentsOfURL()
}
.
.
.
}
URLVisitor.swift
import Cocoa
let queue = NSOperationQueue
class URLVisitor: NSOperation {
.
.
.
func execute() {
let request = Request(URL: URL!, params: params, method: method, jsonParams: jsonParams)
if !self.cookies.isEmpty {
request._setCookies(self.cookies)
}
request._setAuthorizationHeader(self.authorizationHeader)
request.sendRequest()
self.statusCode = request.getStatusCode()
self.isConnected = request.getIsConnected()
}
.
.
.
}
Request.swift
import Cocoa
class Request: NSOperation {
.
.
.
func sendRequest() {
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: URL)
request.HTTPMethod = method
// send jsonParams or params
if jsonParams.count != 0 {
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonParams, options: .PrettyPrinted)
request.setValue("aplication/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPBody = jsonData
} catch {
}
} else {
request.HTTPBody = self.params.dataUsingEncoding(NSUTF8StringEncoding)
}
let task = session.dataTaskWithRequest(request) {
(data, response, error) in
NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookies(self.cookies, forURL: self.URL, mainDocumentURL: nil)
if data != nil {
self.data = data!
do {
let responseHeaders = response as! NSHTTPURLResponse
self.statusCode = responseHeaders.statusCode
switch self.statusCode {
case 200:
print("200: OK. getting contentsOfURL and cookies")
self.contentsOfURL = try NSString(contentsOfURL: self.URL, encoding: NSUTF8StringEncoding)
self.cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookiesForURL(self.URL)!
case 400:
print("400: page not found on web")
case 404:
print("404: page not found on server")
case 407:
print("407: failed authenticate proxy credentials")
default:
print("unable to get statusCode")
}
} catch {
}
} else {
print("\(self.statusCode): unable to get response ")
}
NSThread.sleepForTimeInterval(1.0)
}
task.resume()
}
正确的方法是添加完成处理程序
func sendRequest(completion: () -> Void) {
// ...
let task = session.dataTaskWithRequest(request) {
// ...
completion()
}
task.resume()
}
用法:
let r = Request()
r.sendRequest {
// It's done, do something
}
如果你非要阻塞线程(希望不是主线程),使用信号量。但是请记住,无论请求成功还是失败,都要向信号量发出信号。我见过太多在请求失败时忘记发出信号量的代码,因此应用程序挂断了。
func sendRequest() {
let semaphore = dispatch_semaphore_create(0)
let task = session.dataTaskWithRequest(request) {
// ...
dispatch_semaphore_signal(semaphore)
}
task.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}