NSURL Swift 中的连接:如果 URL 是 404,如何在完成加载后调用函数并重新启动它?
NSURLConnection in Swift: How to call a function when it's finished loading, and restart it if the URL is a 404?
我正在使用 Google 图片 API 生成这样的图片:
let url = NSURL(string: "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=seattle")
let request = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()){ (response, go, error) -> Void in
let go = NSJSONSerialization.JSONObjectWithData(go, options: NSJSONReadingOptions.AllowFragments, error: nil) as [String:AnyObject]
let responseData = go["responseData"] as [String:AnyObject]
然后剩下的代码向下挖掘以找到图像的 URL google api 给出并设置(此处为 var theurl)应用程序中的图像:
let data = NSData(contentsOfURL: theurl!)
self.mainImage.image = UIImage(data: data!)
这行得通,但我需要 1) 停止进程并在发现无法加载的图像 URL 时调用一个函数,以及 2) 在图像完成加载后调用一个函数。
使用完成块并检查你得到的NSError
。
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if let theError = error{
if theError.code == 404{
//Image not available
}else{
//something else
}
}
})
您这里有一些问题需要解决。我认为通过一个例子会更有意义。以下是你完全相同的逻辑,只是稍微更稳健。
import UIKit
class ImageViewController: UIViewController {
var mainImage: UIImageView!
let operationQueue: NSOperationQueue = {
let queue = NSOperationQueue()
queue.maxConcurrentOperationCount = 4
queue.qualityOfService = NSQualityOfService.Utility
return queue
}()
override func viewDidLoad() {
super.viewDidLoad()
downloadImage { [weak self] image in
if let strongSelf = self {
if let image = image {
strongSelf.mainImage.image = image
}
}
}
}
func downloadImage(completion: UIImage? -> Void) {
let url = NSURL(string: "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=seattle")
let request = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(request, queue: self.operationQueue) { [weak self] response, data, error in
if let strongSelf = self {
if error != nil || data == nil {
println(error) // failed to complete original google api request
completion(nil)
return
}
var serializationError: NSError?
if let go = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: &serializationError) as? [String: AnyObject] {
let responseData = go["responseData"] as [String:AnyObject]
let imageURL = NSURL(string: "some_image_url_from_response_data")! // placeholder
let imageRequest = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(imageRequest, queue: strongSelf.operationQueue) { response, data, error in
if error != nil || data == nil {
println(error) // failed to download the image
completion(nil)
return
}
if let image = UIImage(data: data!) {
completion(image)
} else {
println("Failed to create UIImage from downloaded image data")
completion(nil)
}
}
} else {
println(serializationError)
completion(nil)
}
}
}
}
}
异步操作队列
首先,您在主队列上发出异步请求,这违背了异步行为的全部目的。相反,我创建了一个并发操作队列 属性 用于处理下载操作。
弱化/强化
任何时候你在做异步的事情,你必须非常小心保留 self
。保证您始终正确执行的最安全方法是弱化/加强以避免创建保留循环。
嵌套异步请求
您应该使用另一个 sendAsynchronousRequest
调用在后台下载图像。否则,您将在下载图像时阻塞主线程。您的用户不会对这种行为感到满意!
安全反序列化
检查您的 JSON 解析是否成功非常重要。服务器有时会做一些奇怪的事情,您的代码应该能够毫无问题地处理这些事情。
Alamofire
你看过Alamofire了吗?它使类似的事情变得容易得多。
希望这有助于阐明一些问题。
我正在使用 Google 图片 API 生成这样的图片:
let url = NSURL(string: "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=seattle")
let request = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()){ (response, go, error) -> Void in
let go = NSJSONSerialization.JSONObjectWithData(go, options: NSJSONReadingOptions.AllowFragments, error: nil) as [String:AnyObject]
let responseData = go["responseData"] as [String:AnyObject]
然后剩下的代码向下挖掘以找到图像的 URL google api 给出并设置(此处为 var theurl)应用程序中的图像:
let data = NSData(contentsOfURL: theurl!)
self.mainImage.image = UIImage(data: data!)
这行得通,但我需要 1) 停止进程并在发现无法加载的图像 URL 时调用一个函数,以及 2) 在图像完成加载后调用一个函数。
使用完成块并检查你得到的NSError
。
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if let theError = error{
if theError.code == 404{
//Image not available
}else{
//something else
}
}
})
您这里有一些问题需要解决。我认为通过一个例子会更有意义。以下是你完全相同的逻辑,只是稍微更稳健。
import UIKit
class ImageViewController: UIViewController {
var mainImage: UIImageView!
let operationQueue: NSOperationQueue = {
let queue = NSOperationQueue()
queue.maxConcurrentOperationCount = 4
queue.qualityOfService = NSQualityOfService.Utility
return queue
}()
override func viewDidLoad() {
super.viewDidLoad()
downloadImage { [weak self] image in
if let strongSelf = self {
if let image = image {
strongSelf.mainImage.image = image
}
}
}
}
func downloadImage(completion: UIImage? -> Void) {
let url = NSURL(string: "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=seattle")
let request = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(request, queue: self.operationQueue) { [weak self] response, data, error in
if let strongSelf = self {
if error != nil || data == nil {
println(error) // failed to complete original google api request
completion(nil)
return
}
var serializationError: NSError?
if let go = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: &serializationError) as? [String: AnyObject] {
let responseData = go["responseData"] as [String:AnyObject]
let imageURL = NSURL(string: "some_image_url_from_response_data")! // placeholder
let imageRequest = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(imageRequest, queue: strongSelf.operationQueue) { response, data, error in
if error != nil || data == nil {
println(error) // failed to download the image
completion(nil)
return
}
if let image = UIImage(data: data!) {
completion(image)
} else {
println("Failed to create UIImage from downloaded image data")
completion(nil)
}
}
} else {
println(serializationError)
completion(nil)
}
}
}
}
}
异步操作队列
首先,您在主队列上发出异步请求,这违背了异步行为的全部目的。相反,我创建了一个并发操作队列 属性 用于处理下载操作。
弱化/强化
任何时候你在做异步的事情,你必须非常小心保留 self
。保证您始终正确执行的最安全方法是弱化/加强以避免创建保留循环。
嵌套异步请求
您应该使用另一个 sendAsynchronousRequest
调用在后台下载图像。否则,您将在下载图像时阻塞主线程。您的用户不会对这种行为感到满意!
安全反序列化
检查您的 JSON 解析是否成功非常重要。服务器有时会做一些奇怪的事情,您的代码应该能够毫无问题地处理这些事情。
Alamofire
你看过Alamofire了吗?它使类似的事情变得容易得多。
希望这有助于阐明一些问题。