【发布时间】:2020-04-26 08:07:05
【问题描述】:
我使用的是 Swift 4。目标是在将地址簿呈现在视图中之前加载地址簿中的所有数据。在另一种语言(例如js)中,我可以在循环中的每个项目中使用await,然后再告诉视图呈现行。我正在寻找在Swift 4 和UITableViewController 中解决此问题的规范方法。
现在地址簿与Amplify 和GraphQL 一起存储在后端。我有一个User 形式的模型
type User @Model {
id: ID!
name: String!
bio : String!
}
和Contact 的形式
type Contact @model {
ownerId: ID!
userId: ID!
lastOpened: String
}
在ContactController: UITableViewController.viewDidLoad 中,我在ownerId 是我的用户标识令牌的数据库中获取所有Contact,然后我使用此contact 信息创建一个对象。然后对于每个Contact 对象实例,我在初始化对象时在数据库中获取其对应的User。根据这篇文章:Wait until swift for loop with asynchronous network requests finishes executing,我正在使用Dispatch 组,然后在循环完成并且Dispatch 组结束后重新加载UITableView。但是当我print 到控制台时,我看到循环在Contact 对象加载其User 信息之前完成。
代码sn-ps:
class ContactsController: UITableViewController, UISearchResultsUpdating {
var dataSource : [Contact] = []
override func viewDidLoad() {
super.viewDidLoad()
let fetchContactGrp = DispatchGroup()
fetchContactGrp.enter()
self.getMyContacts(){ contacts in
for contact in contacts {
let _contactData = Contact(
userId : contact.userId
, contactId : contact.id
, timeStamp : contact.timeStamp
, lastOpened : contact.lastOpened
, haveAccount: true
)
_contactData.loadData()
self.dataSource.append(_contactData)
}
}
fetchContactGrp.leave()
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
}
函数self.getMyContacts只是一个标准的GraphQL查询:
func getMyContacts( callBack: @escaping ([Contact]) -> Void ){
let my_token = AWSMobileClient.default().username
let contact = Contact.keys
let predicate = contact.ownerId == my_token!
_ = Amplify.API.query(from: Contact.self, where: predicate) { (event) in
switch event {
case .completed(let result):
switch result {
case .success(let cts):
/// @On success, output a user list
callBack(cts)
case .failure(let error):
break
}
case .failed(let error):
break
default:
break
}
}
}
而Contact 对象从数据库中加载User 数据:
class Contact {
let userId: String!
let contactId: String!
var name : String
var bio : String
var website: String
let timeStamp: String
let lastOpened: String
init( userId: String, contactId: String, timeStamp: String, lastOpened: String, haveAccount: Bool){
self.userId = userId
self.contactId = contactId
self.timeStamp = timeStamp
self.lastOpened = lastOpened
self.haveAccount = haveAccount
self.name = ""
self.bio = ""
self.website = ""
}
func loadData(){
/// @use: fetch user data from db and populate field on initation
let _ = Amplify.API.query(from: User.self, byId: self.userId) { (event) in
switch event {
case .completed(let res):
switch res{
case .success (let musr):
if (musr != nil){
let userData = musr!
let em = genEmptyString()
self.name = (userData.name == em) ? "" : userData.name
self.bio = (userData.bio == em) ? "" : userData.bio
self.website = (userData.website == em) ? "" : userData.website
print(">> amplify.query: \(self.name)")
} else {
break
}
default:
break
}
default:
print("failed")
}
}
}
}
【问题讨论】:
-
你使用
DispatchGroup的方式不对。您必须向loadData()添加一个完成处理程序,然后在viewDidLoad的循环内调用enter()并留在loadData()的完成处理程序中。添加group.notify并在闭包中重新加载表格视图。
标签: ios swift uitableview graphql