Abcdefg Abcdefg - 4 months ago 28
Swift Question

Inserting posts into a UICollectionView grid?

Need some guidance on how to approach this. I'm not sure if I'm completely over complicating it or if it is a mess.

I've got a UICollectionView that I want to always have 9 cells and I'm wanting users to be able to insert posts by tapping on a cell..so if they press on cell 8, they make their post, and it shows up there in the 8th cell with potentially 8 other empty cells around it.

I'm posting/pulling these posts from firebase...so I was thinking the flow needed to look something like:

1) Make an empty array of 9 empty [Posts] so that the cells appear and are clickable.

2) On the firebase observer .. if there are say 3 posts able to be returned, it inserts them into the post array / replaces 3 empty posts.

3) I want the posts to show up sort of randomly throughout the grid, so I figured I'd shuffle the array before reloading the data?

4) I don't really care if the posts back from firebase are in the same spot as they were placed by the user, but I want when a user puts a post for it to stay in the same spot as they placed it, so I figured I'd save a variable to firebase like "position : 8" and I'd say something like "If your user uid = the uid of the post, grab the position number and insert that post at that index of the array.

Is this flow way off base or is there a better way to accomplish this? I haven't seen much about inserting items into certain positions into a table view/collection view.

Edit:

func fillWithBlanks() {
for i in 0 ..< 9 {

let blankPost = Post(timestamp: 99999999999999999, picURL: nil, postKey: "") // 100% need a better timestamp there, just filler for now.

postsArray.append(blankPost)

}
}


and then

DataService.ds.REF_POSTS.queryOrderedByChild("timestamp").queryStartingAtValue(cutoff).observeEventType(.ChildAdded, withBlock: { (snapshot:FIRDataSnapshot) in


let time = snapshot.value!["timestamp"] as? Int
let text = snapshot.value!["text"] as? String
let picURL = snapshot.value!["imageURL"] as? String
let key = snapshot.key

let post = Post(timestamp: time!, picURL: picURL!, postKey: key)

self.postsArray[self.selectedPostIndex] = post

self.collectionView.reloadData()

})


So basically on viewDidLoad I'm calling fillWithBlanks(), and then when I select a cell I set the selectedPostIndex to the index clicked on, create a post, and insert it in where I selected.

This works and I tested it by printing out the cell's timestamp when I press on it, and sure enough when I make a post the timestamp is appropraite to the post and not the 99999999.

My massive issue I'm having are the pictures. When I load up I get 9 cells that are empty but when I make a post it sets the picture I set for the post to all 9 cells, and then if I make 2 posts, I get a very Simon-says'ie flashing in all of my cells between the first picture, second picture, and the blank background from the blank cell.

When I make a post I'm saving a download url to firebase and then I have a caching system that downloads the posts or grabs them in. It all worked before trying to implement the blank posts.

Any ideas what would be causing that? I don't understand why appending a new post would do anything to the blank posts I'm making when the app loads up. I'm assuming I'm having some misunderstanding with classes and my Post array/ Post objects aren't what they need to be.




Edit 2:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

let post = postsArray[indexPath.row]

let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MainCell", forIndexPath: indexPath) as! PostCell

if let imageURL = post.picURL {

cell.cellImage.loadImageUsingNSCache(imageURL)


}

return cell

}


and the .loadimagesUsingNSCache comes from :

extension UIImageView {

func loadImageUsingNSCache(urlString: String){


if let cachedImage = imageCache.objectForKey(urlString) as? UIImage {
self.image = cachedImage
return
}
let url = NSURL(string: urlString)
NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) in

if error != nil {
print(error)
return
}
dispatch_async(dispatch_get_main_queue(), {

if let downloadedImage = UIImage(data: data!) {

imageCache.setObject(downloadedImage, forKey: urlString)


self.image = UIImage(data: data!)
}





})


}).resume()
}

Answer

About the problem with the images, remember collection view cells are reusable items, so you need to tell what's the content of every item inside every time you call collectionView(cellForItemAtIndexPath).

That means you need to provide a value for cell.cellImage every time, even if post.picURL is nil. In that case you can say cell.cellImage = nil or show a default empty picture.

Comments