Occasional crash when accessing NSError.localizedDescription
Asked Answered
D

5

5

In a Swift 1.2 app, I have some code that logs NSError objects. In very rare occasions, I get crash reports from Crashlytics indicating that accessing the localizedDescription property caused the crash.

Here's my error logging function:

func trackError(error: NSError)
{
    var props = [String: AnyObject]()

    // CRASHES HERE
    props["NSErrorLocalized"] = error.localizedDescription

    props["NSErrorCode"] = error.code
    props["NSErrorDomain"] = error.domain

    if let userInfo = error.userInfo {
        props["NSErrorUserInfo"] = userInfo
    }

    self.trackEvent("Error", withProperties: props)
}

And here's the call stack reported by Crashlytics:

0 CoreFoundation  CFHash + 129
1 CoreFoundation  CFBasicHashFindBucket + 1204
2 CoreFoundation  CFBasicHashFindBucket + 1204
3 CoreFoundation  CFDictionaryGetValue + 106
4 CoreFoundation  _CFErrorCreateLocalizedDescription + 266
5 Foundation      -[NSError localizedDescription] + 82

I was thinking on directly accessing the NSLocalizedDescriptionKey in error.userInfo instead of via the localizedDescription property, but since the callstack implies that it crashes while accessing a dictionary (which is most probably the userInfo dict), I am afraid that it would not fix anything.

I don't mind not including the localizedDescription in my error log if there is none, but I need a safe way to check if there is one or not without crashing...

Something that might be noteworthy: it seems like the NSError objects that cause this crash are ones that are returned by the Parse SDK. I have no way to be sure of this, but there are some clues in the rest of my logs that seem to imply this.

I have tried to reproduce this by forcing error situations with various calls to the Parse SDK, but my error logging code handle them without any problems and the localizedDescription property returns a valid string without crashing.

Anybody else has seen this and has any clue on what is going on?

Dev answered 22/7, 2015 at 20:31 Comment(3)
did you figure out the reason for the crash while accessing the localizedDescription ?Gamali
I ended up working around it by doing if let localizedDescription = error.userInfo[NSLocalizedDescriptionKey] as? String {} instead of accessing the property directly.Dev
@PascalBourque you should update your post with this answer, it's the solution and it works pretty good.Kosse
D
5

I ended up working around it by doing:

if let localizedDescription = error.userInfo[NSLocalizedDescriptionKey] as? String {}

instead of accessing the property directly.

Dev answered 26/7, 2016 at 3:20 Comment(0)
F
8

One possible way this could crash is if errors are created (in Objective-C) like [NSError new] or [[NSError alloc] init] (i.e., not calling the designated initializer). At least in iOS9, that returns a valid instance, but its internals are not properly initialized and can crash if you call methods on it. Calling -userInfo just returns an empty dictionary, but trying to access other internal state like -localizedDescription and similar methods can do will cause crashes.

Forte answered 8/1, 2016 at 19:44 Comment(1)
This seems like a plausible explanation.Dev
D
5

I ended up working around it by doing:

if let localizedDescription = error.userInfo[NSLocalizedDescriptionKey] as? String {}

instead of accessing the property directly.

Dev answered 26/7, 2016 at 3:20 Comment(0)
H
0

Swift 5

Call from the view

func addBorderCircle() {
    let radius : CGFloat = bounds.width / 2
    let reoundedRect = CGRect(x: .zero, y: .zero, width: bounds.width, height: bounds.height)
    let path = UIBezierPath(roundedRect:  reoundedRect, cornerRadius: .zero)
    let circlePath = UIBezierPath(arcCenter: center, radius: radius, startAngle: .zero, endAngle: Double.pi*2, clockwise: true)
    
    path.append(circlePath)
    path.usesEvenOddFillRule = true
    
    let fillLayer = CAShapeLayer()
    fillLayer.path = path.cgPath
    fillLayer.fillRule = CAShapeLayerFillRule.evenOdd
    fillLayer.fillColor = UIColor.black.cgColor
    fillLayer.opacity = 0.4
    layer.addSublayer(fillLayer)
}
Halley answered 20/7, 2022 at 18:13 Comment(0)
H
0
guard let descriptionKey = self.userInfo[NSLocalizedDescriptionKey] as? String else { return false }
/// use descriptionKey here
Harmless answered 22/9, 2022 at 7:45 Comment(0)
G
-1

Did you check if localizedDescription property is not set to nil? Try something like this...

if let errorLocalizedDescription = localizedDescription as! String {
    props["NSErrorLocalized"] = error.localizedDescription
}
Greatly answered 22/7, 2015 at 20:40 Comment(1)
The property is declared as a non-optional String, so I can't do that.Dev

© 2022 - 2024 — McMap. All rights reserved.