使用 `DispatchGroup` 或某些并发构造来加载数据并顺序填充 `UITableViewController` 中的单元格
Using `DispatchGroup` or some concurency construct to load data and populate cells in `UITableViewController` sequentially
平台:
我在 swift 4 和 xcode 11.4
用例和期望的行为
该应用正在加载可能包含 100 或 1000 项的供稿,假设 500 项。使用 Amplify
的 GraphQL
查询将抓取 500 个项目,然后每个项目将加载 额外的 数据。数据将填充 UITableViewController
中的单元格。理想情况下,此过程将按以下确切顺序发生:
query
500 件商品
- cell_1 加载额外的数据。
- cell_1 渲染数据并显示在
UITableViewController
- cell_2 加载额外的数据。
- cell_2 渲染数据并在
UITableViewController
中显示
...
- cell_500加载额外数据
- cell_500 渲染数据并在
UITableViewController
中显示
因此用户将看到在提要中呈现的单元格“瀑布”。
问题
这似乎是一个需要更好地控制执行的用例,需要这样:https://developer.apple.com/documentation/dispatch/dispatchgroup
我是 Swift 的新手,所以这对我来说有点高级。提供的是 GraphQL
查询的存根,加载附加数据的 class 函数,以及顶层 UITableViewController
。请指导我如何使用 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
附加数据,然后渲染单元格。但无论哪种方式,单元格都不应呈现空数据。
您的示例不完整且无法编译,所以这是简短版本
声明loadData()
func loadData(completion: @escaping () -> Void) {
并确保 completion()
在 任何 情况下被调用(这很重要!)例如
default:
completion()
print("failed")
要正确使用 DispatchGroup
你必须在调用异步任务之前调用 enter
inside 循环并在完成时调用 leave
任务的处理者。最后 outside 循环实现 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
不保留顺序。
平台:
我在 swift 4 和 xcode 11.4
用例和期望的行为
该应用正在加载可能包含 100 或 1000 项的供稿,假设 500 项。使用 Amplify
的 GraphQL
查询将抓取 500 个项目,然后每个项目将加载 额外的 数据。数据将填充 UITableViewController
中的单元格。理想情况下,此过程将按以下确切顺序发生:
query
500 件商品- cell_1 加载额外的数据。
- cell_1 渲染数据并显示在
UITableViewController
- cell_2 加载额外的数据。
- cell_2 渲染数据并在
UITableViewController
中显示
...
- cell_500加载额外数据
- cell_500 渲染数据并在
UITableViewController
中显示
因此用户将看到在提要中呈现的单元格“瀑布”。
问题
这似乎是一个需要更好地控制执行的用例,需要这样:https://developer.apple.com/documentation/dispatch/dispatchgroup
我是 Swift 的新手,所以这对我来说有点高级。提供的是 GraphQL
查询的存根,加载附加数据的 class 函数,以及顶层 UITableViewController
。请指导我如何使用 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
附加数据,然后渲染单元格。但无论哪种方式,单元格都不应呈现空数据。
您的示例不完整且无法编译,所以这是简短版本
声明loadData()
func loadData(completion: @escaping () -> Void) {
并确保 completion()
在 任何 情况下被调用(这很重要!)例如
default:
completion()
print("failed")
要正确使用 DispatchGroup
你必须在调用异步任务之前调用 enter
inside 循环并在完成时调用 leave
任务的处理者。最后 outside 循环实现 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
不保留顺序。