![](/img/trans.png)
[英]Swift - Problem While Downloading Data From Firebase Firestore Asynchronously with DispatchGroup()
[英]Swift - Firebase - Downloading images and data asynchronously leads to wrong display within the collection view cell
我有一個集合視圖,想從 firebase 異步加載圖像和其他數據,並將它們顯示在單元格中。 但是,我當前的方法向文本數據顯示了錯誤的圖像(它們根本不適合),而且,一個特定單元格中的圖像會更改幾次,直到穩定下來(有時是錯誤的,有時是正確的)。
我的代碼
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let photoCell = collectionView.dequeueReusableCell(withReuseIdentifier: "mainViewCollectionCell", for: indexPath) as! MainViewCollectionViewCell
// issue when refreshing collection view after a new challenge has been created
if (hitsSource?.hit(atIndex: indexPath.row) == nil) {
return photoCell
}
let challengeObject = Challenge(json: (hitsSource?.hit(atIndex: indexPath.row))!)
let group = DispatchGroup()
group.enter()
// async call
self.checkIfChallengeIsBlocked(completionHandler: { (IsUserBlocked) in
if (IsUserBlocked) {
return
}
else {
group.leave()
}
}, challengeObject: challengeObject)
group.notify(queue: .main) {
photoCell.setChallengeLabel(title: challengeObject.title)
// async call
photoCell.fetchChallengeImageById(challengeObject: challengeObject)
photoCell.checkIfToAddOrRemovePlayIcon(challengeObject: challengeObject)
// async call
self.dataAccessService.fetchUserById(completionHandler: { (userObject) in
photoCell.setFullName(userObject: userObject)
photoCell.setStarNumber(challengeObject: challengeObject)
}, uid: challengeObject.organizerId)
// async all
self.dataAccessService.fetchAllParticipantsByChallengeId(completionHandler: { (participationArray) in
photoCell.setParticipationNumber(challengeObject: challengeObject, participationArray: participationArray)
}, challengeId: challengeObject.id)
// resize image to collection view cell
self.activityView.removeFromSuperview()
}
return photoCell
}
... 只是為了向您展示我的MainViewCollectionViewCell
class MainViewCollectionViewCell: UICollectionViewCell {
...
public func fetchChallengeImageById(challengeObject:Challenge) {
self.dataAccessService.fetchChallengeImageById(completion: { (challengeImage) in
self.challengeImageView.image = challengeImage
self.layoutSubviews()
}, challengeId: challengeObject.id)
}
和DataAccessService.swift
class DataAccessService {
...
// fetch main challenge image by using challenge id
public func fetchChallengeImageById(completion:@escaping(UIImage)->(), challengeId:String) {
//throws {
BASE_STORAGE_URL.child(challengeId).child(IMAGE_NAME).getData(maxSize: 1 * 2048 * 2048,
completion:({ data, error in
if error != nil {
print(error?.localizedDescription as Any)
let notFoundImage = UIImage()
completion(notFoundImage)
} else {
let image = UIImage(data: data!)!
completion(image)
}
}))
}
...
public func fetchUserById(completionHandler:@escaping(_ user: User)->(), uid:String?) { //
throws{
var userObject = User()
let _userId = UserUtil.validateUserId(userId: uid)
USER_COLLECTION?.whereField("uid", isEqualTo: _userId).getDocuments(completion: {
(querySnapshot, error) in
if error != nil {
self.error = error
print(error?.localizedDescription as Any)
} else {
for document in querySnapshot!.documents {
userObject = User(snapShot: document)
completionHandler(userObject)
}
}
})
}
誰能告訴我需要更改什么才能使文本數據適合單元格中的正確圖像?
通過異步調用來獲取用戶數據,單元格被重用的事實引入了兩個問題:
重新使用單元格時,請確保在異步請求進行期間不顯示前一個單元格的值。 要么讓collectionView(_:cellForItemAt:)
重置這些值,要么更好地讓單元格的prepareForReuse
確保控件被重置。
在異步請求完成處理程序中,在更新之前檢查單元格是否仍然可見。 您可以通過調用collectionView.cellForItem(at:)
完成此操作。 如果生成的cell
為nil
,則該單元格不可見,並且沒有任何可更新的內容。
因此:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let photoCell = collectionView.dequeueReusableCell(withReuseIdentifier: "mainViewCollectionCell", for: indexPath) as! MainViewCollectionViewCell
// make sure to initialize these so if the cell has been reused, you don't see the old values
photoCell.label.text = nil
photoCell.imageView.image = nil
// now in your asynchronous process completion handler, check to make sure the cell is still visible
someAsynchronousProcess(for: indexPath.row) {
guard let cell = collectionView.cellForItem(at: indexPath) else { return }
// update `cell`, not `photoCell` in here
}
return photoCell
}
顯然,如果一個異步完成處理程序發起另一個異步請求,那么您必須重復此模式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.