0

我正在使用 Google Image 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]

然后其余代码深入查找 google api 提供的图像的 URL,并将应用程序中的图像设置为(此处为 var theurl):

let data = NSData(contentsOfURL: theurl!)
self.mainImage.image = UIImage(data: data!)

这可行,但我需要 1)停止进程并在找到无法加载的图像 URL 时调用函数,以及 2)在图像完成加载时调用函数。

4

2 回答 2

3

这里有一些问题需要解决。我认为看一个例子会更有意义。以下是您完全相同的逻辑,只是更健壮一些。

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吗?它使这样的事情变得容易得多。

希望这有助于阐明一些问题。

于 2015-03-17T16:07:51.547 回答
1

使用完成块并检查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
       }
    }
})
于 2015-03-17T15:10:01.570 回答