Reputation: 3246
In my iOS project I use a regular UICollectionView
with a custom cell.
That cell receives some properties and when one of those objects is set I perform some UI updates to the cell.
Though when I scroll I feel a slight glitchy scroll but I don't know how to improve my code in order to make it run smoother.
I have ran Intruments and ran a Time Profiler, when those lags occur the Main Thread CPU usage reaches 100%, as you can see in this image:
Tracing the percentage usage in instruments it came to this:
Tracing further into the png_read_IDAT_data
Now to the code:
In my 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
}
and inside my UICollectionViewCell
whenever the post
variable is set I perform the following UI updates:
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)
}
}
}
Can you help me tracing the issue and how it can be improved?
Thank you.
EDIT
I have commented out the cell.post=
line and by doing that the Main Thread CPU usage went down to about 10%, so one can ensure that the problem is inside the post { didSet{} }
constructor.
Can you see any useful improvements to be done there?
Edit 2
As requested here's the code of the timeAgoDisplay()
function
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"
}
Upvotes: 3
Views: 2895
Reputation: 41
Ah I had this exact same problem, it is trying to recalculate its layoutAttributes every time it scrolls. To combat this try overriding in your custom cell class preferredLayoutAttributesFitting like so:
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
return layoutAttributes
}
Upvotes: 1
Reputation: 7283
I have faced problems like yours as well, thinking that UIImage(data:)
can be used on the background thread and then just apply the result image to the UIImageView
on the main
queue.
That however is not the case, quoting from a great answer on this topic UIImage initWithData: blocking UI thread from async dispatch?:
UIImage doesn't read and decode the image until the first time it's actually used/drawn. To force this work to happen on a background thread, you have to use/draw the image on the background thread before doing the main thread -setImage: call. Many folks find this counter-intuitive. I explained this in considerable detail in another answer.
As above suggests and the answer in the link demonstrates you will have to use/draw
the image on the background thread before using it.
Here is an example I found how you can force decompression on the background thread:
Hope this helps :)
Upvotes: 3
Reputation: 609
You should try applying the cache your images and show them accordingly; have a look to the similar question below and apple documentation -:
Upvotes: 0