用户在我的应用中滚动 UIViewCollectionCells 列表时的奇怪行为(每个单元格中的数据随机更改)

Posted

技术标签:

【中文标题】用户在我的应用中滚动 UIViewCollectionCells 列表时的奇怪行为(每个单元格中的数据随机更改)【英文标题】:Strange behavior when user scrolls the list of UIViewCollectionCells in my app (the data in each cell changes randomly) 【发布时间】:2016-04-08 22:11:07 【问题描述】:

在我的应用程序中,我使用的是UICollectionView,我决定在下面的代码中使用它:

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

所以我有一个带有 UILabelUIImage 的单元格,对于从 json 获取的每个对象,我都会对其进行解析并将用户的数据分配给该单元格。

当我加载窗口时,我会看到带有照片的用户名,但是当我开始滚动浏览收藏视图时,用户的照片会发生变化,并且用户会看到与他们应该拥有的照片不同的照片。

我读过它可能与单元格重用有关(到目前为止我对此一无所知),我只是假设它应该加载一次(当用户打开此面板时)然后保持原样。但是,每次用户滚动该列表时,似乎都会“获取”这些数据。

那么我如何才能准确地解决我的问题并确保每次用户滚动列表时 - 数据都是正确的?

在这里可能有用的另一件事 - 从 url 获取照片的方法 getDataFromUrl

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()

【问题讨论】:

是的,你是对的,这是因为你正在重复使用单元格。此外,您正在进行异步图像提取,所以我认为这是问题,因为 cellForItemAtIndexPath 在您分配图像时已完成执行。您可以尝试预先请求您的图像,并将它们存储在数组或其他东西(缓存)中,然后从该缓存中将它们加载到 cellForItemAtIndexPath 中。 嗯,这是一种完全不同的方法,我没有考虑过,但你的评论让我在隧道中看到了一些光明。但是,我还不知道我应该怎么做,你能帮我看看并举一些简短的例子吗? 【参考方案1】:

Eugene 说的是正确的,但是如果您不想更改代码,那么您已经有太多了。您可以在 SingleUser 上添加一个可选的 UIImage 属性,将其称为“图像”,然后您可以这样说:

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!
  

【讨论】:

在您的示例中,此语句where error == nil else return cell 导致错误Unexpected non-void return value in void function - 我们需要cell 吗? (使用普通的 return 可以正常工作,但是我现在有一个问题,即在列表出现之前未获取数据,因此collection view 不显示图像。 我更新了我的答案。你说的是数据?图像数据?你知道它没有被取走吗?我的意思是说 SingleUser 上的 UIImage 属性应该是可选的,也许这是问题的一部分。 对,不初始化,声明为可选即可。即简单地var image: UIImage? 这样它将初始化为 nil 然后输入 if user.image == nil. 嗯,现在它可以部分工作了,因为好的,图像不会在单元格周围跳跃并粘在上面,但是在打开面板单元格时分配了不同的照片 - 例如单元格号。 1 从用户号获取照片。 3、手机号2 从用户 1 获取图像等。似乎是一些多线程问题... 我不知道面板单元格是什么。也许我不明白你的问题是什么。但我以为您正在异步获取图像。发生这种情况时,会显示单元格,但仍在获取图像。所以用户可以在集合视图上滑动。如果他们将单元格从屏幕上滑出,则该单元格将出列并获得新的 indexPath。 if 语句将检查单元格的当前 indexPath 是否与之前启动 fetch 时相同。如果不是,则该单元格不在屏幕上,因此我们没有将其分配给的单元格,因此没有其他事情可做。

以上是关于用户在我的应用中滚动 UIViewCollectionCells 列表时的奇怪行为(每个单元格中的数据随机更改)的主要内容,如果未能解决你的问题,请参考以下文章

通过从上到下滚动表格来刷新 UITable 内容

在我的 android 应用程序中滚动列表视图时,数据正在消失。我在片段中使用列表视图

iPhone:滚动时展开 UITextView

锁定地图活动

如何实现无限滚动列表视图

如何在我的网站上应用“自动下一个帖子加载”滚动?