用户在我的应用中滚动 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
所以我有一个带有 UILabel
和 UIImage
的单元格,对于从 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 列表时的奇怪行为(每个单元格中的数据随机更改)的主要内容,如果未能解决你的问题,请参考以下文章