使用DispatchGroup或一些并发结构按顺序加载数据并在UITableViewController中填充单元格 [英] Using `DispatchGroup` or some concurency construct to load data and populate cells in `UITableViewController` sequentially

查看:82
本文介绍了使用DispatchGroup或一些并发结构按顺序加载数据并在UITableViewController中填充单元格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是Swift 4和Xcode 11.4

I am on swift 4 and xcode 11.4

该应用程序正在加载一个可能包含100或1000项商品的Feed,比如说500项商品.使用AmplifyGraphQL查询将一次抓取500个项目,然后每个项目将加载其他数据.数据将填充UITableViewController中的单元格.理想情况下,此过程将按以下确切顺序进行:

The app is loading a feed with potentially 100s or 1000s of items, let's say 500 items. The 500 items will be grabbed once using Amplify's GraphQL query, then each item will then load additional data. The data will populate the cells in a UITableViewController. Ideally this process would happen in the following exact sequence:

  1. query 500个项目
  2. cell_1加载其他数据.
  3. cell_1呈现数据并显示在UITableViewController
  4. cell_2加载其他数据.
  5. cell_2渲染数据并显示在UITableViewController
  1. query 500 items
  2. cell_1 load additional data.
  3. cell_1 render data and display in UITableViewController
  4. cell_2 load additional data.
  5. cell_2 render data and display in UITableViewController

...

  1. cell_500加载其他数据
  2. cell_500渲染数据并显示在UITableViewController

因此,用户将看到瀑布". Feed中呈现的单元数.

So the user will see a "waterfall" of cells being rendered in the feed.

这似乎是一个用例,需要对执行进行更好的控制,这将需要以下操作: https://developer.apple.com/documentation/dispatch/dispatchgroup

This seems like a use case that require some finer control of execution, which would need this: https://developer.apple.com/documentation/dispatch/dispatchgroup

我是Swift的新手,所以对我来说有点高级.提供了用于GraphQL查询的存根,用于加载其他数据的类函数以及顶层UITableViewController.请说明如何使用DispatchGroup.

I am new to Swift so this is a bit advanced for me. Provided is the stub for GraphQL query, and class function that loads additional data, and the top level UITableViewController. Please instruct how I would use DispatchGroup.

class Feed: UITableViewController {
    
    var dataSource: [FullItem] = []

    override func viewDidLoad(){
       super.viewDidLoad()
       
       queryItem{ items
           
           for item in items {
              let itemInstanceWithMoreData = FullItem( id: item.id )
              itemInstanceWithMoreData.loadFullData()
           }
         
       }           
    }
}


func queryItems( callBack: @escaping ([Item]) -> Void ){

    _ = Amplify.API.query(from: Item.self, where: predicate) { (event) in
        switch event {
            case .completed(let result):
                switch result {
                    case .success(let xs):
                        callBack(xs)
                    case .failure: 
                        break
                }
            case .failed: 
                break
            default:
                break
        }
    }
}


class FullItem {
    
    id: String
    name: String?
    
    init( id ){ self.id = id; self.name = "" }

    
    func loadData(){

        let _ = Amplify.API.query(from: FullItem.self, byId: self.id) { (event) in
            
            switch event {
                case .completed(let res):
                    switch res{
                        case .success (let musr):
                            if (musr != nil){
                                self.name = musr!.name
                            } else {
                                break
                            }
                        default:
                           break
                    }
                default:
                    print("failed")
            }
        }
    }
}

附录

如果我要的顺序不可行,我还将满足query 500个项目的要求,为每个项目提供load附加数据,然后渲染单元格.但是无论哪种方式,单元格都不应使用空数据进行渲染.

addendum

If the sequence I am asking is not possible, I would also settle for query 500 items, load additional data for each one, then rendering the cells. But either way, the cell should not render with empty data.

推荐答案

您的示例不完整,无法编译,因此是简短版本

Your example is incomplete and doesn't compile so this is the short version

声明loadData()

func loadData(completion: @escaping () -> Void) {

,并确保在任何情况下都调用completion()(这很关键!)

and make sure that completion() is called in any case (this is crucial!) for example

default:
    completion()
    print("failed")

要正确使用DispatchGroup,必须在调用异步任务之前在循环中调用enter 内部,并在任务的完成处理程序中调用leave.在外部末尾,循环实现notify

To use DispatchGroup properly you have to call enter inside the loop before calling the asynchronous task and call leave in the completion handler of the task. At the end outside the loop implement notify

override func viewDidLoad(){
    super.viewDidLoad()

    let group = DispatchGroup()

    queryItems { items

        for item in items {
            group.enter()
            let itemInstanceWithMoreData = FullItem( id: item.id )
            itemInstanceWithMoreData.loadData {
                group.leave()
            }
        }

        group.notify(queue: .main) {
            self.tableView.reloadData()
        }

    }
}

要按顺序顺序插入和更新项目,您需要一个异步Operation和一个串行OperationQueue. DispatchGroup不保留订单.

To insert and update the items serially in order you need an asynchronous Operation and a serial OperationQueue. DispatchGroup doesn't preserve the order.

这篇关于使用DispatchGroup或一些并发结构按顺序加载数据并在UITableViewController中填充单元格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆