异步返回NSData类型

时间:2016-05-07 13:52:51

标签: swift asynchronous functional-programming

我正在学习swift并尝试实现一个函数来下载返回NSData类型,同时还将它保存到类中的另一个变量。

我希望答案能够从根本上改变下面解释的代码,因为这就是我们现在被告知要做的事情。

我无法确定在dispatch_async()函数中正确返回新下载的NSData类型的位置,并且假设它在后台下载,该函数返回的时间早于下载,因此调用函数看到它返回零...

这是我的课程(简化) -

class Photo {
    var title : String
    var url : String
    var data : NSData? = nil

    func imageData(newUrl: String? = nil) -> NSData? {
        /// Check if the current Photo object has either:
        ///     - No data cached -OR-
        ///     - The URL differs from newUrl variable
        if self.data == nil || (newUrl != nil && newUrl != self.url) {

            if let url = NSURL(string: self.url) {
                let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)

                // Asyncronous block
                dispatch_async(queue) {
                if let newData = NSData(contentsOfURL: url) {
                    let mainQueue = dispatch_get_main_queue()
                    dispatch_async(mainQueue, {
                        self.data = newData // Cache data
                    })
                } else {
                    print("Could not download image: '\(self.url)'")
                    self.data = nil
                }
            }
        }
    }
    return self.data
  }

} // End class

1 个答案:

答案 0 :(得分:1)

实现此目的的一种方法是实施completion handler。简单地说,你实际上并没有从函数中返回任何内容,只是将任何数据传递给完成处理程序,然后调用其他地方定义的处理程序。

在您的示例中,您可以将函数定义更改为func imageData(newUrl: String? = nil, completion: (data: NSData?) -> Void)。您现在已经定义了一个名为completion的完成处理程序(闭​​包),其data参数和返回类型Void。然后,您可以在此块中定义处理此函数的处理程序,如下所示:

imageData("someurl") { (data) in
     print(data)
}

这只是将数据打印到控制台,但您可以使用此数据执行任何操作。

完整代码:

    func imageData(newUrl: String? = nil, completion: (data: NSData?) -> Void) {
    /// Check if the current Photo object has either:
    ///     - No data cached -OR-
    ///     - The URL differs from newUrl variable
    if self.data == nil || (newUrl != nil && newUrl != self.url) {

        if let url = NSURL(string: self.url) {
            let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)

            // Asyncronous block
            dispatch_async(queue) {
                if let newData = NSData(contentsOfURL: url) {
                    let mainQueue = dispatch_get_main_queue()
                    dispatch_async(mainQueue, {
                        self.data = newData // Cache data
                        // pass data to the completion block
                        completion(data: self.data)
                    })
                } else {
                    print("Could not download image: '\(self.url)'")
                    self.data = nil
                }
            }
        }
    } else {
        // pass data to the completion block
        completion(data: self.data)
    }
}

还有其他方法可以实现这一点,但我认为这将是最简单的代码更改。您可以查看的其他方式是使用代理NSNotificationNSOperation。有关详情,请参阅以下教程:http://www.appcoda.com/ios-concurrency/https://www.raywenderlich.com/79149/grand-central-dispatch-tutorial-swift-part-1https://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift