2015-11-02 87 views
1

我使用庫上傳圖像。這個庫正在工作異步。異步任務後返回數據

我的功能:

func upload() -> String { 
    let imageData:NSData = UIImageJPEGRepresentation(pureImage!, 100)! 
    var picture="" 
    SRWebClient.POST("http://domain.com/upload.php") 
     .data(imageData, fieldName:"image_field", data: ["username":"test","key":"test"]) 
     .send({(response:AnyObject!, status:Int) -> Void in 
      if status == 200 { 
       let responseJSON = response! as! Dictionary<String, AnyObject> 
       let s_status=responseJSON["status"] as! Int 
       if s_status == 1 { 
        picture=responseJSON["picture"] as! String 
        print(picture) 
       } 
      } 
      },failure:{(error:NSError!) -> Void in 
       picture="" 
     }) 
    return picture 
} 

正如你所看到的,我必須回到圖片名稱。但現在它總是返回空字符串,因爲上傳過程是異步的。如何在上傳過程後返回圖片名稱?

回答

4

很明顯,你不能返回圖片的名字作爲函數的結果,除非你想等待異步任務完成,等待會使它再次成爲同步任務。

有三種非常普遍的方式,使異步任務取得成果:

  1. 傳遞任務的回調(是一個回調函數或完成塊,如果你需要捕獲狀態或引用)。一旦任務完成,它會調用回調。在你的情況下,回調可能會將圖像名稱作爲參數,然後回調代碼需要決定如何處理它。

  2. 如果任務被封裝在一個對象中,則允許該對象擁有一個委託。任務完成後,將調用委託方法。要麼這個方法獲取圖像名稱作爲參數,要麼可以從它委託的對象中查詢圖像名稱(通常你會將對象本身作爲參數傳遞給委託,這是根據Apple的慣例和良好的編碼風格) 。

  3. 發送上傳圖像的通知。圖像名稱可以是通知的對象;或封裝圖像名稱和可能的其他屬性的某個對象。誰有興趣知道何時完成上傳任務可以註冊該通知。

關於上述選項的一些注意事項:

我會用通知小心。雖然它們易於使用,並且非常有用,但是如果需要了解大型項目中的許多組件需要了解有關事件的信息,它們很難調試(您無法在調試器中輕鬆執行代碼流),並且它們會創建一個非常丟失的耦合(這可能是也可能不是可取的),但與通知本身有很強的聯繫。如果需要,通知也不能返回值。

委託始終是一個不錯的選擇,但它強制用戶創建一個實現委託協議的類。如果您需要的不僅僅是單一的回調方法,或者您打算非常頻繁地調用委託方法,這通常只會帶來好處。代表非常適合單元測試。

回調就像一個只有一個回調方法的小委託。如果您在旅途中一般會做出「隨意而忘卻」的任務,並且只需要一次回調,以便在成功和失敗的情況下進行調用;並且它只會被調用一次,並且不需要永久回收它,然後回調通常比代理更可取。它具有委託的所有優點,但它更輕量。

+0

出色答卷。我還會提到在完成塊中傳遞,這是近來很常見的模式,並且類似於使用回調。 –

+0

@DuncanC其實我並不是說回調只是一個函數回調。一個完成塊也只是一個回調,畢竟一個塊只是一個帶有隱含參數的函數(它包含了所有捕獲的狀態,就像你寫塊時捕獲的變量一樣)。我會讓答案更加明顯。 – Mecki

+0

完成塊的另一個優點是塊的代碼可以在線提供,這有助於可讀性。 –

0

您可以使用塊得到回電

func upload(completionHandler : (pictureName : NSString?)-> Void){ 
    let imageData:NSData = UIImageJPEGRepresentation(pureImage!, 100)! 
    var picture="" 
    SRWebClient.POST("http://domain.com/upload.php") 
     .data(imageData, fieldName:"image_field", data: ["username":"test","key":"test"]) 
     .send({(response:AnyObject!, status:Int) -> Void in 
      if status == 200 { 
       let responseJSON = response! as! Dictionary<String, AnyObject> 
       let s_status=responseJSON["status"] as! Int 
       if s_status == 1 { 
        picture=responseJSON["picture"] as! String 
        print(picture) 
        completionHandler(pictureName: picture) 
       } 
      } 
      },failure:{(error:NSError!) -> Void in 
       picture="" 
       completionHandler(pictureName: nil) 
     }) 
} 
1

這是哪門子的,有望被設計爲的問題。你可以實現回調,但如果你有幾個處理的話,它很快就變得難以管理。

做一個大忙,並將PromiseKit導入你的代碼。花半個小時來學習如何使用它。

最後你會喜歡的東西

func upload() -> Promise<String>