0
すべての非同期呼び出しがループ内で終了したときに、dataSourceの更新が終了した後にTableViewを再ロードしようとしました。しかし、postLike.likeUserがforスコープの外側で明確になるようです。ループ内の非同期呼び出しからテーブルビューのdataSourceを変更できません。
class MyTableView: UITableViewController {
let reuseIden = "postLikeCell"
var postLikes: [PostLike]?
var userFetchingCompleted = false
var userFetched: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
startFetchingLikeUsers()
}
func startFetchingLikeUsers(){
if postLikes != nil{
for (index, postLike) in postLikes!.enumerate(){
postLike.likeUser = User(id: postLike.likeUserId, completionHandler: {
// the User initilizer requires to fetch info from the server
(succeed, info) in
if succeed{
self.userFetched += 1
print(self.userFetched)
print(self.postLikes![index].likeUser?.fullname)
if self.userFetched == self.postLikes!.count{
self.userFetchingCompleted = true
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
}
})
}
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return userFetchingCompleted ? (postLikes?.count ?? 0) : 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("postLikeCell", forIndexPath: indexPath) as! PostLikeTableViewCell
print(postLikes![indexPath.row].likeUser) //always print nil
cell.postLike = postLikes![indexPath.row]
return cell
}
}
上記のコードのサンプル出力は
1 //the first iteration
Optional("Nicholas Tse")
user get cleared //it seems the postLike.likeUser gets deInitialized since I have a deInit in my User class
2 //second iteration
Optional("Kesong Xie")
user get cleared
nil //this comes from cellForRowAtIndex
nil
PostLikeクラスのための私の実装のより良い方法非同期呼び出しからのデータソースを更新するためには何
class PostLike{
let postLikeId: Int
let likeTime: String
let likeUserId: Int
unowned var post: Post
weak var likeUser: User? //the user who liked the post
init(postLikeId: Int, likeTime: String, likeUserId: Int, post: Post){
self.postLikeId = postLikeId
self.likeTime = likeTime
self.likeUserId = likeUserId
self.post = post
}
}
更新
私は派遣・グループを使用して自分のコードを変更したが、結果は同じであるが、postLike.likeUserは明らか離れる
func startFetchingLikeUsers(completionHandler:() -> Void){
if postLikes != nil{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { //don't block the main thread
let loadingGroup = dispatch_group_create()
for (index, postLike) in self.postLikes!.enumerate(){
dispatch_group_enter(loadingGroup)
postLike.likeUser = User(id: postLike.likeUserId, completionHandler: {
(succeed, info) in
dispatch_group_leave(loadingGroup)
print(self.postLikes![index].likeUser?.fullname)
})
self.postLikes![index].likeUser = postLike.likeUser
}
dispatch_group_wait(loadingGroup, DISPATCH_TIME_FOREVER)
dispatch_async(dispatch_get_main_queue(), {
completionHandler()
})
})
}
}
出力:postLike.likeUser
は常に割り当て解除を取得する理由
Optional("Nicholas Tse")
user get cleared
Optional("Kesong Xie")
user get cleared
nil
nil
あなたの構造は意味がありません。あなたのUserイニシャライザはどのように構築されますか?通常、戻り値と完了ブロックはありません。また、ここにはスレッドセーフではないコードがたくさんあります。補完ブロックのカウンタをインクリメントするようなもの。あなたはdispatch_groupとdispatch_notifyを使うべきです – Paulw11
私の初期化子の中で、私はすでにdispatch_async(dispatch_get_main_queue()、{})を使っていて、そこから補完ハンドラを呼び出しています。したがって、完了ブロックで行われたすべてがメインスレッドにあります。ユーザーイニシャライザは、サーバーからユーザーのフルネーム、電子メールアドレスなどの情報を取得する必要があります。そのため、完成ブロックを構築する必要があります。完了ブロックが実行されたときにすべてのユーザーデータが使用可能になっていることを確認したい@ Paulw11 –
dispatch_groupが私が探しているものだと思う、thanks @ Paulw11 –