Swift: 阻塞 mainThread 直到函数完成加载数据 / NSURLSession with completionHandler

Swift: Block mainThread until function finished loading data / NSURLSession with completionHandler

我想创建一个函数,它从 url 加载数据,然后 returns 作为 NSData 的 responseData。我想阻塞 mainThread 直到数据完成。这是我目前所拥有的:

函数:

typealias CompletionBlock = (NSData!, NSURLResponse!, NSError!) -> NSData
func requestURL(targetUrl: String, httpMethod: String, httpBody: String, completion: CompletionBlock){

// REQUEST
let target = NSURL(string: targetUrl) // URL
let request = NSMutableURLRequest(URL: target!) // REQUEST

// HTTP-METHOD
var method = httpMethod
if method != "POST" { method = "GET" } // STANDARD: GET
    request.HTTPMethod = method

// HTTP-BODY
let body = httpBody
if body != "" {
    request.HTTPBody = body.dataUsingEncoding(NSUTF8StringEncoding)
}

// NSURLSession
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: completion) // Compiler error!
task.resume()

}

致电:

requestURL(targetURL, "GET", "", { (responseData: NSData!, response: NSURLResponse!, error: NSError!) -> NSData in

        if responseData != nil {
            let resultString = NSString(data: responseData, encoding: NSUTF8StringEncoding) // NSASCIIStringEncoding
            println("DATA:\n\(resultString)")

        }

        if error != nil {
            println("ERROR:\n\(error)")
        }

        return responseData
    })

我在第 21 行的 func 中遇到错误:

let task = session.dataTaskWithRequest(request, completionHandler: completion)

编译器:"Cannot invoke 'dataTaskWithRequest' with an argument list of type '(NSMutableURLRequest, completionHandler: completionBlock)"

至于问题问题:typealias CompletionBlock = (NSData!, NSURLResponse!, NSError!) -> NSData

您的完成处理程序 returns NSData 但它不应该 return 声明中的任何内容:

func dataTaskWithRequest(_ request: NSURLRequest,
   completionHandler completionHandler: ((NSData!,
                              NSURLResponse!,
                              NSError!) -> Void)?) -> NSURLSessionDataTask

这导致了类型错误,因为您提供了错误的 closure type

而且还是比较合理的,因为dataTaskWithRequest被设计成异步的。它creates an HTTP request for the specified URL request object, and calls a handler upon completion。 如果你真的想要发出同步请求,你可以使用旧的NSURLConnectionAPI和sendSynchronousRequest,但你不应该' t 这样做,因为同步请求是一个 非常糟糕的 设计选择:它们阻塞了主 UI 线程并且没有办法取消该请求,除非它自己的错误。这就是为什么 Apple 基于完成处理程序创建了一个新的 NSURLSession API,现在 已弃用 同步请求 iOS 9.

做同步请求非常糟糕,但是这样就可以了

let request = NSURLRequest() //set all url and method and so
var response: NSURLResponse?
var error: NSError?
NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)

重要 同步请求已在 swift 2.0 中删除。

正如丹尼尔所说,这通常是一种不好的做法。任何时候,你必须出去获取数据并等待响应,你应该异步处理。否则,你的 UI 将在主线程挂起,用户很可能会认为你的应用程序崩溃了。

异步工作时,您必须记住您的主线程仍在工作,并且在完成块中接收到数据之前不会有该数据。如果它是必要的,你应该抛出一个 UI 元素让用户知道你正在等待,即。 UIActivityIndi​​catorView