在我的iOS项目中,我使用常规UICollectionView
和自定义单元格。
该单元格接收一些属性,当设置其中一个对象时,我会对单元格执行一些UI更新。
虽然当我滚动时,我感觉到一个轻微的故障滚动,但我不知道如何改进我的代码,以使其运行更顺畅。
我运行了Intruments并运行了Time Profiler,当出现这些滞后时,主线程CPU使用率达到100%,如下图所示:
跟踪它所涉及的工具的使用百分比:
进一步追踪png_read_IDAT_data
现在代码:
在我的UICollectionViewController cellForItem(:_)
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: homeCellId, for: indexPath) as! HomePostCollectionViewCell
cell.post = self.posts[indexPath.item]
cell.delegate = self
cell.layer.cornerRadius = 5
cell.layer.borderWidth = 0.7
cell.layer.borderColor = UIColor.rgb(red: 204, green: 204, blue: 204).cgColor
cell.layer.masksToBounds = true
return cell
}
每当UICollectionViewCell
变量设置时,并在post
内部执行以下UI更新:
public var post: Post? {
didSet {
guard let post = self.post else { return }
userProfileImageView.image = post.user.profileImage
nameLabel.text = post.user.name
titleTextView.text = post.title
creationDateLabel.text = post.creationDate.timeAgoDisplay()
thumbnailImageView.image = post.thumbnail
if backgroundImageOffset != nil {
setBackgroundImageOffset(imageOffset: backgroundImageOffset)
} else {
setBackgroundImageOffset(imageOffset: CGPoint.zero)
}
}
}
你能帮助我追踪这个问题以及如何改进它吗?
谢谢。
修改
我已经注释掉cell.post=
行,并且通过这样做,主线程CPU使用率下降到大约10%,因此可以确保问题在post { didSet{} }
构造函数内。
你能看到有什么有用的改进吗?
修改2
这里要求的是timeAgoDisplay()
函数的代码
func timeAgoDisplay() -> String {
let secondsAgo = Int(Date().timeIntervalSince(self))
let minute = 60
let hour = 60 * minute
let day = 24 * hour
let week = 7 * day
let month = 4 * week
let quotient: Int
let unit: String
if secondsAgo < minute {
quotient = secondsAgo
unit = "second"
} else if secondsAgo < hour {
quotient = secondsAgo / minute
unit = "min"
} else if secondsAgo < day {
quotient = secondsAgo / hour
unit = "hour"
} else if secondsAgo < week {
quotient = secondsAgo / day
unit = "day"
} else if secondsAgo < month {
quotient = secondsAgo / week
unit = "week"
} else {
quotient = secondsAgo / month
unit = "month"
}
return "\(quotient) \(unit)\(quotient == 1 ? "" : "s") ago"
}
答案 0 :(得分:1)
我也遇到了像你这样的问题,认为UIImage(data:)
可以在后台线程上使用,然后只将结果图像应用到UIImageView
队列上的main
。 / p>
然而事实并非如此,引用了关于这个主题的一个很好的答案UIImage initWithData: blocking UI thread from async dispatch?:
UIImage在第一次实际使用/绘制图像之前不会读取和解码图像。要强制在后台线程上执行此工作,您必须在执行主线程-setImage:call之前在后台线程上使用/绘制图像。许多人认为这是违反直觉的。我在另一个answer中详细解释了这一点。
如上所述,链接中的答案表明,在使用它之前,您必须use/draw
后台线程上的图像。
以下是我发现如何在后台线程上强制解压缩的示例:
希望这会有所帮助:)
答案 1 :(得分:0)
您应该尝试应用缓存图片并相应地显示它们; 看看下面的类似问题和苹果文档 - :
答案 2 :(得分:0)
啊我遇到了同样的问题,每次滚动时都会尝试重新计算layoutAttributes。要解决此问题,请尝试覆盖自定义单元格类preferredLayoutAttributesFitting,如下所示:
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
return layoutAttributes
}