I have a CollectionView which I populate from my function loadData, in which I use a DispatchGroup to make sure all information is downloaded correctly. This is then put into two arrays: posts and userInfo, which contain the obvious information: posts has all the data from a specific post including the userID from the author, userInfo has all the data based on userID.
What happens is, it shows everything perfectly, even my autolayout is perfect. When there is no "note", the constraints are changed, it all works. However, when I scroll down, or sometimes the last cell (depending on the height of the cell, I guess, whether the note is visible or not), the note is not shown.
The image above should show what I mean: left has 7 posts, right has 8 posts. In both sides, you can see that the first post (or posts) after scrolling or at the end of the CollectionView don’t contain the note, but the cell is high enough so it could fit.
It is my understanding that the problem occurs in the cellForItemAt method. In the sizeForItemAt method, where the height is calculated based on the length of the note, it all goes well (because the height of the cell adapts nicely).
This is what my cellForItemAt method looks like:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let socialCell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! socialCell
if let userID = posts[indexPath.item].userID {
if let userFirstName = userInfo[userID]?.userFirstName, let userLastName = userInfo[userID]?.userLastName {
socialCell.usernameLabel.text = userFirstName + " " + userLastName
}
}
if let wsName = posts[indexPath.item].postName {
socialCell.postNameLabel.text = wsName
}
socialCell.noteTextView.text = posts[indexPath.item].postNote
if(posts[indexPath.item].postNote == "") {
socialCell.noteTextView.removeFromSuperview()
socialCell.postDetailsView.bottomAnchor.constraint(equalTo: socialCell.noteTextView.bottomAnchor).isActive = false
socialCell.postDetailsView.bottomAnchor.constraint(equalTo: socialCell.postNameLabel.bottomAnchor).isActive = true
}
// all other elements are set here, precisely the same way as the name of the post, so irrelevant
socialCell.layer.shouldRasterize = true
socialCell.layer.rasterizationScale = UIScreen.main.scale
return socialCell
}
I would think it has something to do with indexPath.item – somehow when I scroll or reach the end of the visible area (when cellForItemAt is called, I suppose?), the indexPath gets off, resets, … or something.
Any idea on how to fix this would be sincerely appreciated. Thank you in advance!
EDIT: I am now printing some information because I want to add the profile pictures, but noticed something that could be helpful:
print(userFirstName, " (", indexPath.item, "): ", userProfilePicURL)
I am printing the First Name, the IndexPath and the URL to the Profile Picture, which gives, on loading, this output (it does contain the right URL, I just hid it):
Penny ( 0 ): URL
Penny ( 1 ): URL
Penny ( 3 ): URL
Penny ( 4 ): URL
Penny ( 0 ): URL
Penny ( 1 ): URL
Andrea ( 2 ): URL
Penny ( 3 ): URL
Penny ( 4 ): URL
Andrea ( 5 ): URL
Two observations: the output is returned twice, so the cells are reloaded twice I think. And the first time, indexPath 2 and 5 is missing. Here is how I obtain the data and reload the CollectionView in loadData:
var Ref: DatabaseReference!
Ref = Database.database().reference()
Ref.child("posts").queryOrdered(byChild: "postReverseTimeStamp").observeSingleEvent(of: .value) { (snapshot) in
let dataGroup = DispatchGroup()
for child in snapshot.children {
dataGroup.enter()
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
self.posts.append(post(postID: snap.key, userID: dict["userID"] as! String, postName: dict["postName"] as! String, postNote: dict["postNote"]! as! String, postDuration: dict["postDuration"]! as! Int, postTimeStamp: dict["postTimeStamp"] as! TimeInterval, postLikes: dict["postLikes"]! as! Int, postComments: dict["postComments"]! as! Int))
Ref.child("users").child(dict["userID"] as! String).observeSingleEvent(of: .value) { (snapshot) in
let userValues = snapshot.value as! [String: Any]
userInfo[dict["userID"] as! String] = userData(userFirstName: userValues["userFirstName"] as? String, userLastName: userValues["userLastName"] as? String, userProfilePicURL: userValues["userProfilePicURL"] as? String)
dataGroup.leave()
DispatchQueue.main.async {
self.collectionView?.reloadData()
}
}
}
}
EDIT 2: If I move the reloadData code (including DispatchQueue.main.async) outside the for child statement, it works fine in terms of showing all the notes but then it doesn't show the username and profile picture. Literally no clue what is going on here.
EDIT 3: Still actively trying to resolve this. Haven't been able to do so, but I did add a print statement after each declaration in cellForItemAt, where I set the content of the labels and textviews. I was hoping it would help me find out where the issue can be found, but it does not, as it returns the following:
now working on cell: 0
username: Penny Wise
workout name: Test
note:
now working on cell: 1
username: Penny Wise
workout name: Test
note:
now working on cell: 2
workout name: Another Activity
note: Testing the basic functionality of the feed system
now working on cell: 3
username: Penny Wise
workout name: Activity
note: Nothing special. Just trying out a very long note here, to see if it wraps nicely inside the cell.
now working on cell: 4
username: Penny Wise
workout name: Testing this out!
note: Adding an optional note. Nothing interesting can be found here, but still.
now working on cell: 5
workout name: Some Random Activity
note: With a random note attached to it!
now working on cell: 0
username: Penny Wise
workout name: Test
note:
now working on cell: 1
username: Penny Wise
workout name: Test
note:
now working on cell: 2
username: Andrea Capella
workout name: Another Activity
note: Testing the basic functionality of the feed system
now working on cell: 3
username: Penny Wise
workout name: Activity
note: Nothing special. Just trying out a very long note here, to see if it wraps nicely inside the cell.
now working on cell: 4
username: Penny Wise
workout name: Testing this out!
note: Adding an optional note. Nothing interesting can be found here, but still.
now working on cell: 5
username: Andrea Capella
workout name: Some Random Activity
note: With a random note attached to it!
now working on cell: 0
username: Penny Wise
workout name: Test
note:
now working on cell: 1
username: Penny Wise
workout name: Test
note:
now working on cell: 2
username: Andrea Capella
workout name: Another Activity
note: Testing the basic functionality of the feed system
now working on cell: 3
username: Penny Wise
workout name: Activity
note: Nothing special. Just trying out a very long note here, to see if it wraps nicely inside the cell.
now working on cell: 4
username: Penny Wise
workout name: Testing this out!
note: Adding an optional note. Nothing interesting can be found here, but still.
now working on cell: 5
username: Andrea Capella
workout name: Some Random Activity
note: With a random note attached to it!
It does print everything three times. That's something I also haven't been able to resolve, but not my biggest issue. As you can see, the notes are shown in the print statement, so I can't figure out why they are not being set in these particular cells (with indexPath 4 and 5 in the above case). So I am missing the "Adding an optional note. Nothing interesting can be found here, but still." and "With a random note attached to it!" in my app, as can be seen on the screenshot. It does seem to me that there is something wrong with how I set this note, so this line:
socialCell.noteTextView.text = posts[indexPath.item].postNote
But I have no clue what it could be. I have now tried to add an if let statement, to unwrap it like I did with the other values, but that didn't work either.