2016-07-07 76 views
3

我是一個新的程序員,我很迷茫。混淆關閉和完成句柄

我參加了這個在線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如何知道「數據」在「(data,response,error)」中被假設爲NSData等? ?! 什麼了「dataTaskWithURL」做(停用後則它建立完成處理「

謝謝

+0

閱讀文檔應該有助於https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html – kye

回答

2

這些都是很好的問題!

A closure只是一行代碼行的集合(aka block),您可以像變量一樣對待它,並像函數一樣執行,您可以使用變量名引用閉包,並且可以通過作爲函數調用中的參數,就像任何其他變量一樣,最終在適當的時候執行代碼。閉包可以接受某些參數在其代碼中使用,並且可以包含返回值。

實施例:

這是接受兩個字符串作爲參數並返回字符串的封閉件。

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

因此,下面將打印 「你好傑克!」:

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

閉包也有一個變量的類型(就像"hello"String1Int)。變量類型基於閉包接受的參數和閉包返回的值。因此,由於上面的閉包接受兩個字符串作爲參數並返回一個字符串,因此它的變量類型爲(String, String) -> String。注意:如果沒有返回任何內容(即返回類型爲Void),則可以省略返回類型(因此(Int, String) -> Void(Int, String)相同)。

A 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函數的閉包。

在後一個關閉中(當您調用getDataFromURL時,您在downloadImg中定義的那個關閉),您正在檢查下載的數據是否不爲零,如果不是,則將數據設置爲圖像在UIImageView。調用dispatch_async(dispatch_get_main_queue(), ...)只是確保您按照Apple的規範在主線程上設置新映像(您可以在其他位置閱讀有關線程的更多信息)。

0

做出typealias明白這一點很容易:

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