【问题标题】:API calls blocks UI thread SwiftAPI 调用阻塞 UI 线程 Swift
【发布时间】:2017-06-09 09:08:01
【问题描述】:

我需要在我的 coredata 中同步 Web 数据库,为此我执行服务 api 调用。我正在使用AlamofireSwift 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
    }
}

数据同步接口代码:

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 调用?

【问题讨论】:

  • 更改 DatasyncController()。到 DatasyncController。
  • @Mozahler 如果您建议创建一个静态函数或一个用于调用函数的变量,它们都不会影响性能,尽管我会将这些函数设为静态函数。
  • 是的,我试图提供帮助,因为我无法确定您调用的代码,但您没有向我们展示。
  • 另外,我相信您只在队列中添加了一个工作单元。如果每个 performXXX() 将它们添加到队列中一次,它们可以同时处理。您正在寻找并发性。
  • @Mozahler 没找到你。能再解释一下吗?你是说要创建多个队列吗?

标签: ios swift multithreading asynchronous core-data


【解决方案1】:

您可以这样做以在后台线程上运行:

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

    // Do any processing you want.

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

【讨论】:

  • 它仍然会阻塞 UI。
  • 这会将工作放到后台线程上,但这并不是说其余代码中的某些内容不是然后回调主线程或以其他方式阻塞主线程。您需要显示其余代码供我们确定。
  • 我已经用代码示例更新了我的问题。让我知道可能出了什么问题。
  • 看不到任何明显的东西。 setAPIStatus 方法是否会更新 UI,这可能会导致小问题。 UI以什么方式被阻止?你能不能对它做任何事情或部分具体?
  • setAPIStatus 只是将数据存储在 UserDefaults 中。我没有做任何可以阻止 UI 的事情。我被重定向到具有UITableView 的屏幕,但滚动和didSelectRowAtIndexPath 都不起作用。在应用您的更改之前,我什至没有被重定向到这个新屏幕。
【解决方案2】:

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

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

您确实只将一项放入队列中。

您只添加一次到队列中,因此所有这些“执行”调用都会等待前一个调用完成。如果同时运行它们是安全的,则需要将它们分别添加到队列中。有不止一种方法可以做到这一点,但最重要的是,每次调用 .async {} 时,都会将一项添加到队列中。

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

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

【讨论】:

  • 我无法设置 maxConcurrentOperationCount。我使用的是 DispatchQueue 而不是操作队列。没有操作计数,它仍然会阻塞 UI。
  • 是的。我并不是说这适用于 DispatchQueue。现在我已经了解了如何使用 Alamofire 进行操作,我发现我使用了 Operation 对象,并且涉及到许多类,所以我不建议您采用我的方法。我应该删除这个答案吗? @UpholderOfTruth 是对的。问题的原因不在您显示的代码中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多