2017-06-09 10 views
0

サービスAPIコールを実行する私のコアデータにWebデータベースを同期する必要があります。私はとAlamofireを使用しています。 23のapi呼び出しがあり、異なるcoredataエンティティにほぼ24k行を与えます。API呼び出しブロックUIスレッドSwift

私の問題点:これらのAPIは、ユーザーが待機するのに長い時間ですが、1分間ブロックUIを呼び出します。

私は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または操作キューを使用することをお勧めしますが、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

それでもUIはブロックされます。 – Priyal

+0

それは、バックグラウンドスレッドに作業を入れますが、それはコードの残りの部分が何かを言うのではなく、メインスレッドに戻るか、メインスレッドを何らかの方法でブロックすることではありません。それを判断するには、残りのコードを表示する必要があります。 –

+0

コードサンプルで質問を更新しました。何が間違っているのか教えてください。 – Priyal

0

DispatchQueueは、作業項目の実行を管理します。キューにサブミットされた各作業項目は、システムによって管理されるスレッドのプール上で処理されます。

私は通常、AlamofireでNSOperationQueueを使用しますが、その概念は似ています。非同期キューを設定すると、メイン(UI)スレッドとは独立に作業を実行できるので、アプリケーションはフリーズしません(ユーザー入力を拒否します)。作業はまだまだ時間がかかりますが、終了を待つ間はプログラムがブロックされません。

実際には、1つのアイテムをキューに入れるだけです。

キューには一度しか追加されないため、これらの「実行」コールはすべて前回の完了を待ちます。それらを同時に実行することが安全な場合は、それらをそれぞれ別々にキューに追加する必要があります。これを行うには複数の方法がありますが、最終行は.async {}を呼び出すたびに1つの項目をキューに追加します。

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

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

maxConcurrentOperationCountを設定できません。 DispatchQueueを操作キューではなく使用しています。操作回数がなければ、UIはまだブロックされます。 – Priyal

+0

はい。私はそれがDispatchQueueのために働くことを示唆していませんでした。 Alamofireのやり方を見てきましたが、私はOperationオブジェクトを使用していますが、いくつかのクラスが含まれていることがわかります。私はあなたのアプローチを採用することをお勧めしません。この回答を削除する必要がありますか? @UpholderOfTruthが正しいです。あなたの問題の理由は、あなたが示したコードにありません。 – Mozahler

関連する問題