令人困惑的闭包和完成句柄

时间:2016-07-07 01:01:13

标签: iphone xcode swift closures completionhandler

我是一名新的程序员而且非常迷失。

我正在参加这个在线iOS开发课程,我正在配置集合视图单元格。 但是,使用了闭包和完成句柄,之前从未提及过。

import UIKit

class PersonCell: UICollectionViewCell {

@IBOutlet weak var img: UIImageView!

func configureCell(imgUrl: String) {
    if let url = NSURL(string: imgUrl) {
        downloadImg(url)
    }        
}

func downloadImg(url: NSURL) {
    getDataFromURL(url) { (data, response, error) in
        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            guard let data = data where error == nil else {return}
            self.img.image = UIImage(data: data)
        }
    }
}

func getDataFromURL(url: NSURL, completion: ((data: NSData?, response: NSURLResponse?, error: NSError?) -> Void)) {

    NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
        completion(data: data, response: response, error: error)
    } .resume()

}
}

有人可以向我解释在“getDataFromURL”函数之后完成处理程序正在做什么。还有什么关闭呢?是“(数据,响应,错误)”传递? swift如何知道“数据”在“(数据,响应,错误)”中被假定为NSData等? “dataTaskWithURL”之后的闭包是做什么的(它是否设置了完成处理程序“?

谢谢!

2 个答案:

答案 0 :(得分:2)

这些都是好问题!

closure只是代码行的集合(也称为块),您可以将其视为变量并像函数一样执行。您可以引用具有变量名称的闭包,并且可以像在任何其他变量中一样将函数调用中的闭包作为参数传递,最终在适当时执行代码。闭包可以接受在其代码中使用的某些参数,它可以包含返回值。

示例:

这是一个闭包,它接受两个字符串作为参数并返回一个字符串。

let closure: (String, String) -> String = { (a: String, b: String) -> String in
                                              return a + b
                                          }

因此,以下将打印" Hello Jack!":

print(closure("Hello ", "Jack!"))

闭包也有一个变量类型(就像"hello"String1Int)。变量类型基于闭包接受的参数和闭包返回的值。因此,由于上面的闭包接受两个字符串作为参数并返回一个字符串,因此其变量类型为(String, String) -> String。注意:当没有返回任何内容(即返回类型为Void)时,您可以省略返回类型(因此(Int, String) -> Void(Int, String)相同)。

completion handler是一个闭包,可以传递给某些函数。当函数完成时,它会执行闭包(例如,当视图完成动画到屏幕上,文件完成下载时等)。

示例:

"!完成"将在视图控制器完成演示时打印。

let newClosure: () -> Void = { () -> Void in
    print("Done!")
}
let someViewController = UIViewController(nibName: nil, bundle: nil)
self.presentViewController(someViewController, animated: true, completion: newClosure)

让我们专注于您首先编写的getDataFromURL函数。它需要两个参数:类型为NSData的变量和类型为(NSData?, NSURLResponse?, NSError?) -> Void的闭包。因此,闭包(名为completion)采用类型为NSData?NSURLResponse?NSError?的三个参数,并且不返回任何内容,因为这是您定义闭包的方式在函数声明中。

然后拨打getDataFromURL。如果您阅读documentation,您将看到在加载任务完成时执行作为第二个参数传递给此函数的闭包。 dataTaskWithURL的函数声明定义了闭包接受并返回的变量类型。在这个闭包中,您将调用传递给getDataFromURL函数的闭包。

在后一个闭包中(您在调用downloadImg时在getDataFromURL中定义的闭包),您正在检查您下载的数据是否为零,如果不是,则表示您是然后将数据设置为UIImageView中的图像。 dispatch_async(dispatch_get_main_queue(), ...)调用只是确保您根据Apple的规范在主线程上设置新图像(您可以在其他地方阅读有关线程的更多信息)。

答案 1 :(得分:0)

制作一个类型来理解这很容易:

typealias Handle = (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void
//the func should be 
func getDataFromURL(url: NSURL, completion: Handle)
//when you call it. it needs an url and an Handle
getDataFromURL(url:NSURL, completion: Handle)
// so we pass the url and handle to it 
getDataFromURL(url) { (data, response, error) in
        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            guard let data = data where error == nil else {return}
            self.img.image = UIImage(data: data)
        }
    }
//setp into the func 
func getDataFromURL(url: NSURL, completion: Handle){
    // call async net work by pass url
    NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
        // now data / response / error  we have and we invoke the handle 
        completion(data: data, response: response, error: error)
        } .resume()

}
hope it be helpful :D