0

Our latest release has caused a crashing bug for 1% of our user base. I'm completely stuck with this as it can't be reproduced in our staging environment.

Firebase Crashlytics is throwing this error:

Crashed: NSOperationQueue 0x282d76da0 (QOS: UNSPECIFIED)
0  MyApp                         0x102d38c40 String.toExpiryDate() + 339 (Extensions.swift:339)
1  MyApp                         0x102d3f628 closure #1 in ApiService.unlockVariablePass(credit:complete:) + 235 (ApiService.swift:235)
2  MyApp                         0x102d34324 partial apply for closure #1 in HttpClient.post(url:token:username:password:body:callback:) + 53 (HttpClientService.swift:53)
3  MyApp                         0x102d693e0 partial apply for closure #1 in NSURLSession.dataTask(with:completionHandler:) + 20 (URLSessionProtocol.swift:20)
4  MyApp                         0x102d69210 thunk for @escaping @callee_guaranteed (@guaranteed Data?, @guaranteed NSURLResponse?, @guaranteed Error?) -> () (<compiler-generated>)
5  CFNetwork                      0x1936f1688 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 32
6  CFNetwork                      0x193705220 __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 176
7  Foundation                     0x193b81ef8 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16
8  Foundation                     0x193a8e3e0 -[NSBlockOperation main] + 72
9  Foundation                     0x193a8d8c8 -[__NSOperationInternal _start:] + 740
10 Foundation                     0x193b83c7c __NSOQSchedule_f + 272

I have checked the server and the logs prove that the expiry_date has always been provided in the correct format. It has never been null.

{"expiry_date": "2019-07-05 20:00:36"}

The client code:

try? self.httpClient.post(url: url, token: ServerUrlFabric.shared.getTokenForAPI(), username: kc_username, password: kc_password, body: creditDict) { (data, response, error) in
            if let error = error {
                log(error.localizedDescription)
                complete(false, nil, ServiceError.invalidSession)
            } else if let httpResponse = response as? HTTPURLResponse {
                switch (httpResponse.statusCode) {
                case 201:
                    let json = try! JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<String, Any>
                    let expiryDate = (json["expiry_date"] as! String).toExpiryDate()
                    complete(true, expiryDate, nil)

Extension:

extension String {
    func toExpiryDate() -> Date {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        formatter.timeZone = TimeZone(abbreviation: "UTC")
        return formatter.date(from: self)!
    }
}

What have I missed, please?

Todd Burner
  • 2,202
  • 12
  • 15
Houman
  • 64,245
  • 87
  • 278
  • 460
  • You should always set a fixed formatter locale (usually "en_US_POSIX") when parsing a fixed-format string. – Martin R Jul 05 '19 at 17:42
  • Compare https://developer.apple.com/library/archive/qa/qa1480/_index.html, https://stackoverflow.com/questions/6613110/what-is-the-best-way-to-deal-with-the-nsdateformatter-locale-feechur, https://stackoverflow.com/a/16706425/1187415, or https://stackoverflow.com/a/40702569/1187415 – Martin R Jul 05 '19 at 17:44
  • @MartinR Thank you so much for your reply. Like this? `let posix = Locale(identifier: "en_US_POSIX") formatter.locale = posix` – Houman Jul 05 '19 at 17:53
  • 1
    Yes, or simply `formatter.locale = Locale(identifier: "en_US_POSIX")`. Note that this must be set first, before setting `dateFormat`. – Martin R Jul 05 '19 at 17:55
  • Ah Thank you, otherwise I would have just introduced a new bug. :-D – Houman Jul 05 '19 at 17:58

0 Answers0