![](/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.