API调用阻止UI线程Swift

时间:2017-06-09 09:08:02

标签: ios swift multithreading asynchronous core-data

我需要在我的coredata中同步web数据库,我为此执行服务api调用。我正在使用Alamofire Swift 3。有23个api调用,在不同的coredata实体中提供近24k行。

我的问题:这些api调用会阻止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或Operation Queue,尽管尝试DispatchQueues对我不起作用。

我做错了吗? 我怎么能不阻止UI并同时执行api调用?

2 个答案:

答案 0 :(得分:2)

您可以执行此操作以在后台线程上运行:

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

    // Do any processing you want.

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

答案 1 :(得分:0)

DispatchQueue管理工作项的执行。提交到队列的每个工作项都在系统管理的线程池上处理。

我通常将NSOperationQueue与Alamofire一起使用,但概念类似。设置异步队列时,允许独立于主(UI)线程执行工作,以便您的应用程序不会冻结(拒绝用户输入)。这项工作仍然需要很长时间,但是你的程序在等待完成时不会阻塞。

你真的只把一个项目放入队列。

您只需要向队列添加一次,因此所有这些"执行"呼叫等待前一个完成。如果同时运行它们是安全的,则需要将它们中的每一个分别添加到队列中。有多种方法可以做到这一点,但每次调用.async {}时,底线就是将一个项目添加到队列中。

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

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