ios - 使用 `DispatchGroup` 或一些并发结构来加载数据并按顺序填充 `UITableViewController` 中的单元格
问题描述
平台:
我在 swift 4 和 xcode 11.4
用例和期望的行为
该应用程序正在加载可能包含 100 或 1000 件商品的提要,比如说 500 件商品。Amplify
使用's查询将抓取 500 个项目GraphQL
,然后每个项目将加载附加数据。数据将填充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
查询的存根、加载附加数据的类函数以及顶层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
内部leave
调用,并在任务的完成处理程序中调用。最后在循环外实现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()
}
}
}
要按顺序插入和更新项目,您需要一个 asynchronousOperation
和一个 serial OperationQueue
。DispatchGroup
不保留订单。
推荐阅读
- hive - 在 Avro 中声明简单时间戳的正确方法是什么
- sql-server - 为什么 SSIS OData 连接器突然开始引发 VS_ISBROKEN 异常?
- ssl - Boringssl 可以在裸机 ARM 系统中工作吗?
- php - 序列号在我的分页中的每一页中从 1 开始
- arrays - 将一个数组分成 k 段以最大化按位和
- amazon-web-services - 如何将 AWS Elasticsearch 迁移到 Azure Elasticsearch?
- python - 在 DataFrame 的开头而不是结尾处附加一个子字符串
- python - 使用 tile 从二维数组构造 3 维数组
- arrays - 如何在 VHDL 中初始化记录数组?
- mysql - 查询中的错误 (1064): 'INTERSECT(SELECTfriend_id FROM user_friend_list WHERE user_id = '20' and frien' 在第 3 行附近的语法错误