Search code examples
iosswift2nsdateexc-bad-accessfoundation

EXC_BAD_ACCESS in NSDate formatting extention


I'm writing an extension for NSDate which provides some failable initializers. The end goal here is to get a date time string from an API and parse it into an NSDate, e.g.

let createdAt = NSDate(apiDateTimeString: "2016-03-29T18:33:49+06:00")
let createdAt = NSDate(apiDateTimeString: "2016-03-29T18:33:49.730+06:00")

The date time string can take one of 2 formats:

  • yyyy-MM-dd'T'HH:mm:ssZZZZZ
  • yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ

Here is what the extension looks like:

import Foundation

public extension NSDate {

    // MARK: Custom Initializers

    public convenience init(date: NSDate) {
        self.init(timeInterval: 0.0, sinceDate: date)
    }

    public convenience init?(dateString: String, formatString: String) {
        let formatter = NSDateFormatter()
        formatter.dateFormat = formatString
        formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
        if let date = formatter.dateFromString(dateString) {
            self.init(date: date)
        } else {
            return nil
        }
    }

    public convenience init?(apiDateTimeString: String?) {
        guard let dateString = apiDateTimeString else {
            return nil
        }
        if NSDate(dateString: dateString, formatString: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") != nil {
            self.init(dateString: dateString, formatString: "yyyy-MM-dd'T'HH:mm:ssZZZZZ")
        } else {
            self.init(dateString: dateString, formatString: "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ")
        }
    }
}

When I try to use this, it get an EXC_BAD_ACCESS at if NSDate(dateString: dateString, formatString: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") != nil

Any help figuring out why this isn't working is appreciated.

EDIT: I forgot to add: this worked with Swift 2.1, and quit working with Swift 2.2


Solution

  • This is an issue in Swift 2.2. For more information, see SR-704: EXC_BAD_ACCESS on returning nil from a failable initializer of NSObject subclass. Looks like it was fixed in the mainline branch, but didn’t make it into the final Swift 2.2 release. Expect it to be fixed in the next point update.

    As a temporary workaround, make sure to to always initialize the object before returning nil from a failable initializer (or throwing from a throwing initializer). That is, insert self.init() before every return nil statement.

    Edit: This issue has been fixed in Swift 2.2.1/Xcode 7.3.1. It should no longer be necessary to initialize the instance before returning nil.