Strange behavior when user scrolls the list of UIV

2019-09-18 10:18发布

In my app I'm using UICollectionView and I've decided to use it as in the code below:

class UserList: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

@IBOutlet weak var tview: UICollectionView!
let reuseIdentifier = "cell" 
var items = NSMutableArray()

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let cell = tview.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! MyCollectionViewCell

    let user:SingleUser =  self.items[indexPath.item] as! SingleUser   

    cell.username.text = user.name


        if let checkedUrl = NSURL(string: user.photo) {
            cell.userImg.contentMode = .ScaleAspectFit

            getDataFromUrl(checkedUrl) { (data, response, error)  in
                dispatch_async(dispatch_get_main_queue()) { () -> Void in
                    guard let data = data where error == nil else { return }
                    print(response?.suggestedFilename ?? "")
                    cell.userImg.image = UIImage(data: data)
                }
            }

        }

    return cell
}

So I have a cell with a UILabel and UIImage and for each object fetched from json I parse it and I assign user's data to that cell.

When I load the window I see usernames with photos of them, but when I start scrolling through the collection view the photos of users change and users get different photos than they should have.

I've read it might be something related to cell reusing (so far I know nothing about it), I just assumed it should be loaded once (when user opens this panel) and then left as it is. However it seems like this data is "fetched" each time user scrolls that list.

So how can I exactly fix my problem and be sure each time user scrolls the list - the data will be correct?

One more thing that might be useful here - method getDataFromUrl that fetches photos from urls:

func getDataFromUrl(url:NSURL, completion: ((data: NSData?, response: NSURLResponse?, error: NSError? ) -> Void)) {
    NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
        completion(data: data, response: response, error: error)
        }.resume()
}

1条回答
走好不送
2楼-- · 2019-09-18 11:22

What Eugene said is correct, but if you don't want to change the code you have already too much. You can add an optional UIImage property on SingleUser, call it "image," then you can say something like:

if user.image == nil{
  getDataFromUrl(checkedUrl) { (data, response, error)  in
    dispatch_async(dispatch_get_main_queue()) { () -> Void in
     guard let data = data where error == nil else { return }
     print(response?.suggestedFilename ?? "")
     let image  = UIImage(data: data)
     user.image = image
     //Check if this cell still has the same indexPath, else it has been dequeued, and image shouldn't be updated
     if collectionView.indexPathForCell(cell) == indexPath
     {
       cell.userImg.image = image
     }
    }
   }
  }else{
    cell.userImg.image = user.image!
  }
}
查看更多
登录 后发表回答