簡體   English   中英

Swift - Firebase - 異步下載圖像和數據會導致集合視圖單元格中的顯示錯誤

[英]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)
            }
        }
    })
}

誰能告訴我需要更改什么才能使文本數據適合單元格中的正確圖像?

通過異步調用來獲取用戶數據,單元格被重用的事實引入了兩個問題:

  1. 重新使用單元格時,請確保在異步請求進行期間不顯示前一個單元格的值。 要么讓collectionView(_:cellForItemAt:)重置這些值,要么更好地讓單元格的prepareForReuse確保控件被重置。

  2. 在異步請求完成處理程序中,在更新之前檢查單元格是否仍然可見。 您可以通過調用collectionView.cellForItem(at:)完成此操作。 如果生成的cellnil ,則該單元格不可見,並且沒有任何可更新的內容。

因此:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM