Search code examples
iosswifturl-encoding

Swift URL String encoding crashing on iOS?


I have a URL string with variables appended to the end, like so:

.../create?title=My Apartment

I would like to escape any non-valid characters (like the space), but when I try to do so, I crash in both the simulator and on my device (iOS 8.0) using the following:

NSLog("Item1: \(item)")
NSLog("Item2: \(item.title)")

if let scrubbed = item.title.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet()) {
    NSLog("Scrubbed: \(scrubbed)")
} else {
    NSLog("Nope!")
}

What I see on the simulator, is this:

2014-09-24 16:59:19.120 MyApp[16406:171349] Item1: MyApp.PostItem
2014-09-24 16:59:19.121 MyApp[16406:171349] Item2: My Apartment
2014-09-24 16:59:19.125 MyApp[16406:171349] Scrubbed: My              0X0P+0partment

Note the strangeness of that scrubbed string. It crashes some time later complaining about a poorly-constructed NSURL object, unsurprisingly.

When I run this on my device, I crash with an EXC_BAD_ACCESS on the NSLog() statement that's trying to print Scrubbed:

2014-09-24 17:04:37.378 MyApp[4346:2048259] Item1: MyApp.PostItem
2014-09-24 17:04:37.379 MyApp[4346:2048259] Item2: My Apartment

(lldb) po scrubbed

error: <EXPR>:1:1: error: non-nominal type '$__lldb_context' cannot be extended
extension $__lldb_context {                            
^
<EXPR>:11:5: error: 'PostManager.Type' does not have a member named '$__lldb_wrapped_expr_3'
    $__lldb_injected_self.$__lldb_wrapped_expr_3(     
    ^                     ~~~~~~~~~~~~~~~~~~~~~~
(lldb) 

How can I figure out what's going on here? I would have expected to see Nope! printed in the console before having it crash like this. The String value in the model object is being provided by a UITextField.

Edit: I was able to get some NSData output from the pre-scrubbed value:

NSLog("Data: \(item.title.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false))")
...
2014-09-24 17:18:43.620 MyApp[4367:2051348] Data: Optional(<4d792041 70617274 6d656e74>)

Edit 2: I can confirm this crashes in Xcode, and passes in a playground. Seems to be a bug - but where? Xcode? Compiler? Runtime?

Edit 3: This bug only crops up if I attempt to print out the variable value with NSLog(). If I completely avoid doing this, and just use the variable, everybody's happy.


Solution

  • Looks like escaping with NSCharacterSet.URLHostAllowedCharacterSet() generates strange unicode string which forces crash in NSLog in case using this string as first parameter.

    There are a few ways to avoid this and you definitely should use them:

    • As far as you are using this in URL query you definitely should use different characher set - NSCharacterSet.URLQueryAllowedCharacterSet().

    • Use print/println

    • Pass scrubbed to NSLog as a parameter NSLog("Scrubbed: %@", scrubbed)

    Any of those "workarounds" solves the problem.