2
\$\begingroup\$

I would like to create two date formatters only on first call. In Objective-C I would use dispatch_once() but now working in Swift. Am I doing it correctly? My code is based on example that was using class instead of static but it looks like it's Swift 2.0 doesn't support it yet.

class HomeContentItem : NSObject {
    var hideDescription:Bool = false
    var expanded:Bool = true

    var imageURL:String?
    var titleShort:String?
    var textBody:String?
    var sectionName:String?
    var dateString: String?
    var watermarkImage:UIImage?

    var moreTappedAction: ((AnyObject) -> (Void))?
    var sectionNameTappedAction: ((AnyObject) -> (Void))?
    var selectedItemAction: ((AnyObject) -> (Void))?

    static let sameDayFormatter = { (Void) -> NSDateFormatter in
        let formatter = NSDateFormatter()
        formatter.dateFormat = "hh:mm"
        return formatter
        }()

    static let differentDayFormatter = { (Void) -> NSDateFormatter in
        let formatter = NSDateFormatter()
        formatter.dateFormat = "yyyy/MM/dd"
        return formatter
        }()

    func setDate(date:NSDate) {
        if date.isSameDateAs(NSDate()) {
            self.dateString = HomeContentItem.sameDayFormatter.stringFromDate(date)
        } else {
            self.dateString = HomeContentItem.differentDayFormatter.stringFromDate(date)
        }
    }
}

And extention to date:

extension NSDate {
    func isSameDateAs(date : NSDate) -> Bool {
        let firstCalendar = NSCalendar.currentCalendar().components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day], fromDate: self)
        let secondCalendar = NSCalendar.currentCalendar().components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day], fromDate: date)
        return (firstCalendar.day == secondCalendar.day &&
            firstCalendar.month == secondCalendar.month &&
            firstCalendar.year == secondCalendar.year)
    }
}
\$\endgroup\$
  • \$\begingroup\$ I updated my code. I also added NSDate extention. \$\endgroup\$ – Szu Aug 6 '15 at 12:33
  • \$\begingroup\$ With your edit, is it working 100% correctly? According to swiftstub.com/884086817/?v=gm it is still broken \$\endgroup\$ – Ismael Miguel Aug 6 '15 at 13:26
  • \$\begingroup\$ Sure it is. I'm working on swift 2.0, maybe that's why swiftstub doesn't work properly. Anyway isSameDateAs extention is not important part of review. \$\endgroup\$ – Szu Aug 6 '15 at 13:37
3
\$\begingroup\$

This isn't the way to compare two dates...it violates one of my commandments. We can & should use NSCalendar's compareDate method:

extension NSDate {
    func isSameDayAs(date: NSDate) -> Bool {
        let calendar = NSCalendar.currentCalendar()
        let dif = calendar.compareDate(self, toDate: date, toUnitGranularity: .DayCalendarUnit)
        return dif = .OrderedSame
    }
}

Moreover, your date formatter methods don't have any business in the view controller. These make more sense also as NSDate extension methods. However, creating NSDateFormatters is actually a pretty expensive operation. We don't want to do it more often than necessary. So, let's make a struct to handle one formatter per style we want:

extension NSDate {
    private struct Formatters {
        static let timeFormatter = { (Void) -> NSDateFormatter in
            let formatter = NSDateFormatter()
            formatter.dateFormat = "hh:mm"
            return formatter
        }()

        static let yearMonthDayFormatter = { (Void) -> NSDateFormatter in
            let formatter = NSDateFormatter()
            formatter.dateFormat = "yyyy/MM/dd"
            return formatter
        }()
    }

    var timeString: String {
        get {
            return Formatters.timeFormatter.stringFromDate(self)
        }
    }

    var yearMonthDayString: String {
        get {
            return Formatters.yearMonthDayFormatter.stringFromDate(self)
        }
    }
}

Importantly, using this approach makes unit testing (which you should definitely be doing) quite easy. And, we've put code in places where it makes sense.

\$\endgroup\$
2
\$\begingroup\$

Yes this is correct, I believe class for classes was renamed to static. The only thing that I would change is the line

static let secondFormatter = { (Void) -> NSDateFormatter in

to

static let secondFormatter : NSDateFormatter = {

which is more readable, because you can immediately see that it's an NSDateFormatter.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.