2017-06-09 83 views
0

我需要在我的coredata中同步Web數據庫,爲此我執行服務api調用。我正在使用AlamofireSwift 3。有23個API調用,在不同的coredata實體中提供近24k行。API調用塊UI線程Swift

我的問題:這些api調用阻止用戶界面一分鐘,這是用戶等待很長時間。

我嘗試使用DispatchQueue和執行在後臺線程任務,但毫無效果。這是我嘗試:

let dataQueue = DispatchQueue.init(label: "com.app.dataSyncQueue") 
dataQueue.async { 
     DataSyncController().performStateSyncAPICall() 
     DataSyncController().performRegionSyncAPICall() 
     DataSyncController().performStateRegionSyncAPICall() 
     DataSyncController().performBuildingRegionSyncAPICall() 

     PriceSyncController().performBasicPriceSyncAPICall() 
     PriceSyncController().performHeightCostSyncAPICall() 

     // Apis which will be used in later screens are called in background 
     self.performSelector(inBackground: #selector(self.performBackgroundTask), with: nil) 

    } 

從DataSyncController API調用:

func performStateSyncAPICall() -> Void { 
     DataSyncRequestManager.fetchStatesDataWithCompletionBlock { 
      success, response, error in 
      self.apiManager.didStatesApiComplete = true 
     } 
    } 

DataSyncRequestManager代碼:

static func fetchStatesDataWithCompletionBlock(block:@escaping requestCompletionBlock) { 

    if appDelegate.isNetworkAvailable { 

     Util.setAPIStatus(key: kStateApiStatus, with: kInProgress) 

     DataSyncingInterface().performStateSyncingWith(request:DataSyncRequest().createStateSyncingRequest() , withCompletionBlock: block) 
    } else { 
     //TODO: show network failure error 
    } 
} 

DataSyncingInterface代碼:

func performStateSyncingWith(request:Request, withCompletionBlock block:@escaping requestCompletionBlock) 
{ 
    self.interfaceBlock = block 
    let apiurl = NetworkHttpClient.getBaseUrl() + request.urlPath! 
    Alamofire.request(apiurl, parameters: request.getParams(), encoding: URLEncoding.default).responseJSON { response in 

      guard response.result.isSuccess else { 
       block(false, "error", nil) 
       return 
      } 

      guard let responseValue = response.result.value else { 
       block (false, "error", nil) 
       return 
      } 
      block(true, responseValue, nil) 
     } 
} 

我知道很多類似的問題已經發布在Stackoverflow上,大多數情況下建議使用GCD或Operation Queue,儘管DispatchQueues不適用於我。

我做錯了什麼? 我該如何阻止UI並同時執行api調用?

+0

變化DatasyncController()。到DatasyncController。 – Mozahler

+0

@Mozahler如果你建議創建一個靜態函數或調用函數的變量,它們都不會影響性能,但我會將這些函數設置爲靜態函數。 – Priyal

+0

是的,我試圖提供幫助,因爲我無法確定您撥打的代碼,但您沒有向我們顯示。 – Mozahler

回答

1

你可以這樣做是爲了在後臺線程運行:

DispatchQueue.global(qos: .background).async { 

    // Do any processing you want. 

    DispatchQueue.main.async { 
     // Go back to the main thread to update the UI. 
    } 
} 
+0

它仍然阻止用戶界面。 – Priyal

+0

這將把工作放到後臺線程上,但這並不是說在代碼的其餘部分內沒有回調到主線程或以其他方式阻塞主線程。您需要顯示剩餘的代碼以供我們確定。 –

+0

我用代碼示例更新了我的問題。讓我知道什麼是錯的。 – Priyal

0

DispatchQueue管理的工作項目的執行。提交給隊列的每個工作項都在由系統管理的線程池上處理。

我通常使用NSOperationQueue與Alamofire,但概念是相似的。設置異步隊列時,您可以獨立於主(UI)線程執行工作,以便您的應用程序不會凍結(拒絕用戶輸入)。這項工作仍需要很長時間,但是您的程序在等待完成時不會阻止。

你真的只把一個項目放入隊列中。

你加入到隊列中只有一次,因此所有那些「執行」呼叫等待前一個完成。如果可以安全地同時運行它們,則需要將它們分別添加到隊列中。有多種方法可以做到這一點,但底線是您每次調用.async時添加一個項目到隊列中。

dataQueue.async { 
    DataSyncController().performStateSyncAPICall() 
} 

dataQueue.async { 
    DataSyncController(). performRegionSyncAPICall l() 
} 
+0

我無法設置maxConcurrentOperationCount。我正在使用DispatchQueue而不是操作隊列。沒有操作數量,它仍然阻止用戶界面。 – Priyal

+0

是的。我並不是建議它適用於DispatchQueue。現在我已經看過我如何用Alamofire做到這一點,我看到我已經使用了Operation對象,並且涉及了很多類,所以我不建議您採用我的方法。我應該刪除這個答案嗎? @ UpholderOfTruth是對的。您的問題的原因不在您顯示的代碼中。 – Mozahler