2015-11-04 27 views
2

我想傳遞一個函數作爲參數,因爲我正在處理Web服務,並且我注意到代碼是重複的。如何在Swift中傳遞未知參數和返回值作爲參數的函數

片段1

Service.getAllVouchersUsingCallback() { (response, data, error) -> Void in 
    guard let statusCode = response?.statusCode else { 
     Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION) 
     return 
    } 

    switch statusCode { 
     case 200: 
      self.loadVouchersWithData(data!) 
     case 503: 
      Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE) 
     default: 
      Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE) 
    } 
} 

片段2

Service.getAllCategoriesUsingCallback { (response, data, error) -> Void in 

    guard let statusCode = response?.statusCode else { 
     Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION) 
     return 
    } 

    switch statusCode { 
     case 200: 
      self.loadAndGetCategories(data!, withInialText: "Category ") 
     case 503: 
      Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE) 
     default: 
      Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE) 
    } 
} 

的一部分是重複的是,當狀態代碼爲nil會發生什麼,我有要執行的操作時,迴應是200。我猜函數簽名應該是這樣的:

func dealWithWebServiceResponse(response: NSURLResponse?, withData data: NSData?, whichActionIs action: whateverFunctionType) 

所以,我想知道我可以通過什麼功能,即參數的任何數字或任何返回值的數量,因爲在這種情況下,我路過只是數據,但可能在將來我需要另一種功能。

在此先感謝。

+0

目前還不清楚這是重複的哪一部分,因爲你只給出了一個例子。你能證明第二個會看起來像是有重複的代碼嗎? (這可能是除了'NSData - >()'以外的任何東西?) –

+0

@RobNapier,我剛剛更新了我的問題。正如你所看到的代碼非常相似,但是當響應變化爲200時的動作。 – lmiguelvargasf

回答

3

這是探索返回函數的函數的一個很大的問題。所以我們有這樣的代碼塊:

guard let statusCode = response?.statusCode else { 
    Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION) 
    return 
} 

switch statusCode { 
case 200: 
    // <<================ Right here, we want to do "something different" 
case 503: 
    Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE) 
default: 
    Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE) 
} 

那麼我們該怎麼做「有點不同?」我們傳遞一個函數。該功能需要採取「數據」,因爲這是我們唯一的。你可能會認爲這個函數需要「其他的東西」(比如「Category」),但它確實沒有。 這個的代碼並不知道任何關於「Category」的信息。在項目的早些時候,其他的東西必須處理那部分。唯一不同的是數據。因此,讓我們假設我們有一個功能第二:

let success: (NSData) -> Void = ... 
... 
case 200: 
    success(data!) 
... 

我們只是想弄清楚success在這種情況下。那麼,在你的第一個例子,它是:

{ self.loadVouchersWithData($0) } 

,並在你的第二個例子是:

{ self.loadAndGetCategories($0, withInialText: "Category ") } 

這些都是採取NSData不返回任何兩種功能,就像我們想要的。

所以我們想要一種方法來取代第一塊代碼和插件這個變化的東西。我們需要一個函數,它需要一個「成功」函數並返回一個「處理所有東西」函數。讓我們一起寫出來:

func successHandler(success: (NSData) -> Void) -> (NSHTTPURLResponse?, NSData?, NSError?) -> Void { 
    return { (response: NSHTTPURLResponse?, data: NSData?, error: NSError?) in 
     guard let statusCode = response?.statusCode else { 
      Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION) 
      return 
     } 

     switch statusCode { 
     case 200: 
      success(data!) // <==== Here's the part that changes! 
     case 503: 
      Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE) 
     default: 
      Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE) 
     } 
    } 
} 

哇,那第一行是一個很奇怪的。讓我們來看看它:

func successHandler(success: (NSData) -> Void) -> (NSHTTPURLResponse?, NSData?, NSError?) -> Void { 

這是一個功能,那需要一個函數,它接受一個NSData返回任何結果,而整個函數返回一個函數,它的響應,數據,錯誤元組,並且沒有返回。冥想一會兒。你真的想讓它沉浸其中,因爲它真的很強大。好吧,希望這開始有點沉淪,所以我要繼續前進。語法是非常巨大的,所以雨燕給了我們一個很好的技巧來簡化它,叫柯里:

func successHandler(success: (NSData) -> Void)(response: NSHTTPURLResponse?, data: NSData?, error: NSError?) { 
    guard let statusCode = response?.statusCode else { 
     Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION) 
     return 
    } 

    switch statusCode { 
    case 200: 
     success(data!) // <==== Here's the part that changes! 
    case 503: 
     Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE) 
    default: 
     Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE) 
    } 
} 

現在的聲明是:

func successHandler(success: (NSData) -> Void)(response: NSHTTPURLResponse?, data: NSData?, error: NSError?) { 

(我知道這可能似乎並不簡單得多,但確實如此,並且它確實使功能的其餘部分更簡單。)

這是(幾乎)與前面的聲明完全相同。暫時斡旋那條線。請注意0​​雙圓括號語法。請注意我最後可以放棄-> Void

柯里格就像現在傳遞一些參數,並能夠在稍後通過其他參數。

好的,那我們怎麼用呢?

Service.getAllVouchersUsingCallback(successHandler{ self.loadVouchersWithData($0) }) 
Service.getAllCategoriesUsingCallback(successHandler{ self.loadAndGetCategories($0, withInialText: "Category ") }) 

我們把我們的東西,想要一個(響應,數據錯誤),並通過它調用successHandler與需要數據的函數的結果。

而且應該刪除所有你正在談論的重複。這是一個特別複雜的版本,因爲有很多級別的功能。但它也表明了這種技術的強大。

您可能需要暫時擱置一會兒,然後回到較簡單的介紹,例如Introduction to Function Currying in Swift。那麼,當這是有道理的,回到這個。

+0

@RobNaiper,哇!我非常感謝你爲我的問題提供答案的時間。你的回答非常明確,而且很有價值。我非常感謝你的一切。 – lmiguelvargasf

+0

@RobNapier真正的史詩和有益的博覽會!我希望在即將到來的項目中使用它。 – spirographer

+1

@Rob Naiper,對我有效的是'self.successHanler {self.loadVouchersWithData($ 0)}(response:response,whichDataIs:data)'。 – lmiguelvargasf

相關問題