5

I am having some performance issues in my iOS app while transforming dates that come in a 2013-12-19 00:00:00.000000 format to a medium style date (Dec 25, 2014) and to a double value (epoch). According to the Xcode profiler the two functions that do this process (bellow) are taking approximately 60% of my execution time

I would like to know how to improve this code or if there is a more efficient way to get what I need.

static func getMediumDate(dateString: String) -> (NSString)? {

    // Get the: yyyy-MM-dd
    let shorDate = dateString[dateString.startIndex..<dateString.startIndex.advancedBy(10)]

    let dateFormatter = NSDateFormatter()
    dateFormatter.locale = NSLocale(localeIdentifier: "en_US")
    dateFormatter.dateFormat = "yyyy-MM-dd"

    let stringFormatter = NSDateFormatter()
    stringFormatter.locale = NSLocale(localeIdentifier: "en_US")
    stringFormatter.dateFormat = "yyyy-MM-dd"
    stringFormatter.dateStyle = .MediumStyle

    let newDate = dateFormatter.dateFromString(shorDate)

    if (newDate != nil){
        return stringFormatter.stringFromDate(newDate!)
    }else{
        return nil
    }
}

static func getSortDate(dateString:String) -> Double{

    // Get the: yyyy-MM-dd
    let shorDate = dateString[dateString.startIndex..<dateString.startIndex.advancedBy(10)]

    let dateFormatter = NSDateFormatter()
    dateFormatter.locale = NSLocale(localeIdentifier: "en_US")
    dateFormatter.dateFormat = "yyyy-MM-dd"

    let newDate = dateFormatter.dateFromString(shorDate)

    let value = newDate?.timeIntervalSince1970

    if value < DBL_MIN{
        return 0
    }else if value > DBL_MAX{
        return DBL_MAX
    }else if value != nil{
        return value!
    }else{
        return 0
    }
}
Evgeny Karkan
  • 8,782
  • 2
  • 32
  • 38
Caponte
  • 401
  • 1
  • 11
  • 20
  • 1
    Creating date formatters and setting the `dateFormat` property are expensive operations. Create each date formatter once and store it in a static property and reuse them. – dan Jul 25 '16 at 18:04

2 Answers2

11

NSDateFormatter is notoriously slow. You should create it once, cache it and reuse the same instance rather than creating a new instance every time.

For example, you can do the following:

extension NSDateFormatter {
    private static let standardDateFormatter: NSDateFormatter = {
        let dateFormatter = NSDateFormatter()
        dateFormatter.locale = NSLocale(localeIdentifier: "en_US")
        dateFormatter.dateFormat = "yyyy-MM-dd"
        return dateFormatter
    }()
}
dzl
  • 908
  • 11
  • 32
  • 1
    On iOS 7 and later `NSDateFormatter` is thread safe. - `Thread Safety` chapter from https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/index.html#//apple_ref/occ/cl/NSDateFormatter – Evgeny Karkan Jul 25 '16 at 18:48
  • how would you use it? with some kind of getter? could you give me an example? – Caponte Jul 25 '16 at 19:47
5

Creating NSDateFormatter instance - is a complex CPU consuming task.
It is better to use it once or create shared instance.

Take a look at this thread describing best NSDateFormatter practices - Whats the best practice for NSDateFormatter in Swift?

Also more info on this you can find in Data Formatting Guide from Apple:

Cache Formatters for Efficiency

Creating a date formatter is not a cheap operation. If you are likely to use a formatter frequently, it is typically more efficient to cache a single instance than to create and dispose of multiple instances. One approach is to use a static variable.

So, to refactor your code - you should replace initialisation of 3 NSDataFormatter instances with function that inits and returns only 1 shared instance (1 memory address), then use returned instance.

Community
  • 1
  • 1
Evgeny Karkan
  • 8,782
  • 2
  • 32
  • 38
  • Thank you very much for your answer, It is the right answer but Danny Zlobinsky answered first. I will up vote the answer nevertheless. – Caponte Jul 25 '16 at 19:48