如何在OperationsQueue完成所有操作时重新加载UITableView

时间:2018-03-25 03:53:51

标签: swift uitableview nsoperationqueue nsoperation

我正在尝试通过调用UITableView更新.reloadData()中的单元格,但它会在进程完成之前重新加载数据,因此不会真正更新任何内容,因为它从中获取数据的数组仍为空。我编写代码的方式是它产生一堆API调用,每个调用都是Swift OperationOperationQueue执行这些操作。现在需要做的是完成所有任务后调用self.tableView.reloadData()。我已经尝试将它放在一个操作的完成块中,但它不是主线程,因此不会执行。

任何帮助将不胜感激。

编辑:我已经尝试使用OperationQueueOperationQueue.main的线程更改为主线程并添加在包含{{1的所有其他操作完成后运行的最终操作}}。虽然这允许我重新加载self.tableView.reloadData(),但它会导致UI滞后。 (我在UITable中进行刷新,使得主线程使用明显。)

示例代码:

UITableView

4 个答案:

答案 0 :(得分:1)

有两种可能的方法:

  1. 创建一个新的操作,当其他所有操作完成后,您要执行该操作,我将调用"完成操作"。然后,每次创建现有的单个操作之一时,将该操作作为依赖项添加到"完成操作"。然后,当您完成添加所有单个操作(并将每个操作作为依赖项添加到"完成操作)后,将完成操作添加到主队列。在所有其他单独的操作完成之前,它不会被激活。

    例如:

    let queue = OperationQueue()
    queue.maxConcurrentOperationCount = 4
    
    let completionOperation = BlockOperation {
        print("done")
    }
    
    for _ in 0 ..< 10 {
        let operation = ...
        completionOperation.addDependency(operation)
        queue.addOperation(operation)
    }
    
    OperationQueue.main.addOperation(completionOperation)
    

    请注意,这假设您已仔细创建了您的操作,因此操作无法完成,直到各个操作中的任务完成为止。值得注意的是,如果您的操作正在启动一个本身就是异步任务(例如网络请求)的任务,请确保将Operation子类定义为&#34;异步&#34;操作(isAsynchronous返回true)并确保完成后正确执行isFinished / isExecuting KVO。

  2. 另一种方法是使用调度组。每次创建一个单独的操作时,enter组(不在操作本身,而是在创建这些操作并将其添加到操作队列中时)。然后,作为您个人操作中的最后一项任务,leave该组。然后,当您完成所有单个操作的添加后,您可以创建一个调度组notify,您可以在主队列上进行调度。然后,当所有单个操作时,您的调度组通知块将触发。

    例如:

    let queue = OperationQueue()
    queue.maxConcurrentOperationCount = 4
    
    let group = DispatchGroup()
    
    for _ in 0 ..< 10 {
        group.enter()
        let operation = BlockOperation {
            ...
            group.leave()
        }
        queue.addOperation(operation)
    }
    
    group.notify(queue: .main) {
        print("done")
    }
    
  3. 我倾向于选项1(保持在操作队列范例内),但这两种方法都有效。

答案 1 :(得分:0)

从完成块中,您可以使用Grand Central Dispatch在主线程上执行另一个块。使用

DispatchQueue.main.async {
    self.tableView.reloadData()
    // your other code here
}

答案 2 :(得分:-1)

使用DispatchGroup。

let dispatchGroup = DispatchGroup()

dispatchGroup.enter()

asyncTask1() { dispatchGroup.leave() }

asyncTask2() { dispatchGroup.leave() }

asyncTask3() { dispatchGroup.leave() }

dispatchGroup.notify(queue: .main) {
//reload table }

答案 3 :(得分:-1)

您可以使用完成处理程序示例:

func reloadData(completion: @scaping (completed: Bool)->Void) {
     //your code
     completion(true)
}

调用func

reloadData() {(completed : Bool) in
    if completed {
      tableView.reloadData()
    }    
}