1

So let me explain, I am using Parse, which holds some film reviews for me. I am populating these into a UITableView controller from Parse. This all works fine - no issues.

What I'd like to do...

Display another image in the cell (held locally) only when that object was created in Parse within the last week. So essential, the additional image I want to add is a small banner saying 'New'. If I added the film to my Parse database on the 1st of the month, then I want this 'New' image banner to also be displayed for the next 7 days in the cell. On the 8th day, the 'New' image banner removes and it just displays the cell as normal.

I know there is a automatic column in Parse that gets created for every object called "createdAt", so I assume this is the part I need to work with. I just can't figure out how to add this as code, as I've never really worked with Dates from Parse.

Below is how the cell would be displayed for reference:

enter image description here

So I just want that 'New' image in red displayed for 7 days from the "createdAt" date from Parse.

Can anyone help show me how to add this code?

Thanks in advance.

UPDATED:

EDIT: My CustomTableViewCell.swift

class CustomTableViewCell: PFTableViewCell {

@IBOutlet weak var filmNameLabel: UILabel!

@IBOutlet weak var filmReleaseDateLabel: UILabel!

@IBOutlet weak var directedByLabel: UILabel!

@IBOutlet weak var cellFilmImage: PFImageView!


// MARK: - Star Rating Images

@IBOutlet weak var star1: UIImageView!

@IBOutlet weak var star2: UIImageView!

@IBOutlet weak var star3: UIImageView!

@IBOutlet weak var star4: UIImageView!

@IBOutlet weak var star5: UIImageView!


@IBOutlet weak var bannerView: UIImageView!



func bindData(filmObject: PFObject) {

    if let filmName = filmObject["FilmName"] as? String {
        filmNameLabel.text = filmName
    } else {
        filmNameLabel.text = "Untitled"
    }

    if let dateReleased = filmObject["DateReleased"] as? String {
        filmReleaseDateLabel.text = "In UK cinemas \(dateReleased)"
    } else {
        filmReleaseDateLabel.text = "N/A"
    }

    if let directedBy = filmObject["DirectedBy"] as? String {
        directedByLabel.text = "Directed by \(directedBy)"
    } else {
        directedByLabel.text = "N/A"
    }

    // Show the banner if the object was created within the last 7 days
    if let createdAt = filmObject["createdAt"] as? NSDate {
        let calendar = NSCalendar.currentCalendar()
        let sevenDaysAgo = calendar.dateByAddingUnit(.Day, value: -7, toDate: NSDate(), options: [])

        // Show banner if sevenDaysAgo <= createdAt
        if sevenDaysAgo!.compare(createdAt) != .OrderedDescending {
            // Show the banner imageView
            bannerView.hidden = false
        } else {
            bannerView.hidden = true
        }
    } else {
        bannerView.hidden = true
    }



    // MARK: - Star Rating System
    if let ourRating = filmObject["OurRating"] as? Double {

        star1.image = getStarImage(1, forRating: ourRating)
        star2.image = getStarImage(2, forRating: ourRating)
        star3.image = getStarImage(3, forRating: ourRating)
        star4.image = getStarImage(4, forRating: ourRating)
        star5.image = getStarImage(5, forRating: ourRating)

    }

    let imageFromParse = filmObject.objectForKey("filmPosterImage") as? PFFile
    imageFromParse!.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
        let image: UIImage! = UIImage(data: imageData!)!
        self.cellFilmImage?.image = image
    })

}

}

My TableViewController.swift showing cellForRowAtIndexPath

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {

    var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! CustomTableViewCell!
    if cell == nil {
        cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
    }

    if object != nil {
        cell.bindData(object!)
    }

    return cell
}
Nick89
  • 2,948
  • 10
  • 31
  • 50

1 Answers1

1

Should be as straight-forward as adding the UIImageView to your cell (via storyboard prototype, xib, or whatever you like) with the banner loaded from your project's image assets.

Initialize the banner imageView to be hidden and then in your tableView's cellForRowAtIndexPath check to see if the associated review was created within the last 7 days. Depending on if you use a standard UITableView and query for the reviews yourself, or if you use a PFQueryTableViewController from the ParseUI framework, the specific implementation will vary, but the gist of it will be the following.

let calendar = NSCalendar.currentCalendar()
let sevenDaysAgo = calendar.dateByAddingUnit(.Day, value: -7, toDate: NSDate(), options: [])

if let reviewDate = object?.createdAt {
    // sevenDaysAgo <= reviewDate
    if sevenDaysAgo.compare(reviewDate) != .OrderedDescending {
        // Show the banner imageView
        cell.bannerView.hidden = false
    }
}

Edit: Here is the updated version of cellForRowAtIndexPath and CustomTableViewCell

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! CustomTableViewCell!
    if cell == nil {
        cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
    }

    if object != nil {
        cell.bindData(object!)
    }
    return cell
}

class CustomTableViewCell: PFTableViewCell {

    @IBOutlet weak var filmNameLabel: UILabel!
    @IBOutlet weak var filmReleaseDateLabel: UILabel!
    @IBOutlet weak var directedByLabel: UILabel!
    @IBOutlet weak var bannerView: UIImageView!
    // ... other outlets

    func bindData(filmObject: PFObject) {

        if let filmName = filmObject["FilmName"] as? String {
            filmNameLabel.text = filmName  
        } else {
            filmNameLabel.text = "Untitled"
        }

        if let dateReleased = filmObject["DateReleased"] as? String {
            filmReleaseDateLabel.text = "In UK cinemas \(dateReleased)"  
        } else {
            filmReleaseDateLabel.text = "N/A"
        }

        if let directedBy = filmObject["DirectedBy"] as? String {
            directedByLabel.text = "Directed by \(directedBy)"  
        } else {
            directedByLabel.text = "N/A"
        }

        // Show the banner if the object was created within the last 7 days
        if let createdAt = filmObject.createdAt {
            let calendar = NSCalendar.currentCalendar()
            let sevenDaysAgo = calendar.dateByAddingUnit(.Day, value: -7, toDate: NSDate(), options: [])

            // Show banner if sevenDaysAgo <= createdAt
            if sevenDaysAgo!.compare(createdAt) != .OrderedDescending {
                // Show the banner imageView
                bannerView.hidden = false
            } else {
                bannerView.hidden = true
            }
        } else {
            bannerView.hidden = true
        }

        // ... bind the rest of the data from the PFObject to the cell

    }

}
Russell
  • 3,099
  • 2
  • 14
  • 18
  • I use PFQueryTableViewController – Nick89 Dec 18 '15 at 20:04
  • Have you had a chance to give this a go yet? Edit your original post with your current implementation of `cellForRowAtIndexPath` if you'd like help stitching it all together – Russell Dec 18 '15 at 20:32
  • I have added my implementation of `cellForRowAtIndexPath` - Thanks for walking me through this... – Nick89 Dec 18 '15 at 21:20
  • Thanks very much. I make sense of it all, however, I think i'm being a bit stupid here, Im having an issue Initialising the banner imageView to be hidden first. As my cell has a `customTableViewCell` my image is added in that .swift file. And then it's not recognised in my TableViewController - does that make sense? – Nick89 Dec 18 '15 at 22:02
  • 1
    Sure does. In your `customTableViewCell` .swift file, that's where you will want to initialize the banner imageView to be hidden. If you're still having trouble with it, try adding your code for that as well. Hard to debug something if I can't see it haha – Russell Dec 18 '15 at 22:26
  • Haha very true! Okay I've added a bit more code in my question above. It's the code thats in my `customeTableViewCell.swift` file. I think i'm going wrong Initialising the bannerView Image wrong... – Nick89 Dec 18 '15 at 22:55
  • 1
    It's better to offload the data extraction and binding to the cell to the `CustomTableViewCell` implementation. See my update for the implementation. Create the imageView in the storyboard or xib you already have and there is a button in the attributes inspector to have it default to hidden. If you're still having issues with it not displaying then there could be something wrong with the outlet connection. Don't forget to upvote helpful comments/answers :) – Russell Dec 19 '15 at 05:13
  • Don't worry I'll definitely mark the questions/comments :) I've just been updating my code, but I can't get it to work :( - I've checked twice and my bannerView image is definitely linked up with the Outlet connection correctly. But the image just doesn't show for any of the cells. (and I do have objects in Parse that apply to the date - i've added a test object to check) Ive added the code you showed me to the `CustomTableViewCell.swift` file. I've also set the image to be hidden in main.Storyboard. I don't get any errors, it just doesn't show the image. Any thoughts? – Nick89 Dec 19 '15 at 17:14
  • 1
    Try breaking this down to figure out where it's gone awry -- let's get the image to show up first. Change the attribute in the storyboard so it isn't hidden and also comment out any code which uses the hidden property. If it's still not showing after all that, then the issue is probably unrelated – Russell Dec 20 '15 at 02:08
  • Okay So it's no longer hidden from the storyboard, and in the 3 places we refer to `bannerView.hidden` in the `CustomTableViewCell.swift`, I have commented them out. When I build and run the bannerView image shows (as expected)... – Nick89 Dec 20 '15 at 14:09
  • Found the issue -- it was an error in the date comparison logic. I've just double checked it using a playground and it should be solid now. Also refactored it to use 7 days instead of 8 so it's more intuitive. Let me know how it goes! – Russell Dec 20 '15 at 21:29
  • Okay so I added that but no different. I may be getting confused...Above your edit section, there is another block of code, that is different to the block of code below it in your edit. Where does that go? – Nick89 Dec 20 '15 at 22:03
  • That was the block of code from the original answer before you listed your code. You only need to bottom code for `CustomTableViewCell` and `cellForRowAtIndexPath`. Make it so it's no longer hidden from the storyboard, that shouldn't be needed anyways since it will be shown or hidden using the provided code – Russell Dec 20 '15 at 22:10
  • Ah I thought that, was just checking. Okay, so it still hasn't changed it. Ive checked again by unhiding it from the storyboard and commenting out the 3 lines referring to `bannerView.hidden` and then I see the image. But when I have them uncommented and the image set to hidden in the storyboard *(I've checked both ways)*, I don't see the `bannerView` image next to any of the reviews... – Nick89 Dec 20 '15 at 22:23
  • Try adding some breakpoints to figure out what's going wrong. It could have an issue retrieving the 'createdAt' date if it's not spelled the same as it is in Parse – Russell Dec 20 '15 at 22:29
  • So i've been playing around with break points and found no issues. Ive checked all spelling in Parse and everything is as it should be. – Nick89 Dec 20 '15 at 23:18
  • Could you elaborate a bit more? Are you reaching code within the date comparison? Is the createdAt date being properly retrieved/accessed? – Russell Dec 21 '15 at 04:12
  • hmmm i think you may have hit the nail on the head there. I'm not convinced I'm actually accessing the createdAt date from Parse. Is there a simple way you know of that I could check this, in the code that we've got. (I really do appreciate your help with this so far Russell!) – Nick89 Dec 21 '15 at 12:49
  • You can inspect the variable once you set a breakpoint or you can add a `print` statement to output the value to the console. Hard to tell what else it could be without seeing the code myself. Updating the code in the OP with exactly what you have may be useful – Russell Dec 21 '15 at 21:38
  • I have updated my question to show my full code for the `CustomTableViewCell.swift` and my `cellForRowAtIndexPath`. I have tried doing the `print(createdAt)` - but nothing prints to the console... – Nick89 Dec 22 '15 at 12:21
  • 1
    Found the issue and it is a total face palm haha. The created at date should be accessed as a property rather than retrieving it using a key. So instead of using `filmObject["createdAt"] as? NSDate` we should use `filmObject.createdAt`. That's why the conditional was always failing! See my updated answer with the corrected code and let me know if this is finally resolved :) – Russell Dec 22 '15 at 16:35
  • 1
    Absolutely spot on! It works beautifully! I can't thank you enough for your help and patience to help me with this! – Nick89 Dec 22 '15 at 17:03