29

How do I prevent NSJSONSerialization from adding extra backslashes to my URL strings?

NSDictionary *info = @{@"myURL":@"http://www.example.com/test"};
NSData data = [NSJSONSerialization dataWithJSONObject:info options:0 error:NULL];
NSString *string = [[NSString alloc] initWithData:policyData encoding:NSUTF8StringEncoding];
NSLog(@"%@", string);//{"myURL":"http:\/\/www.example.com\/test"}

I can strip the backslashes and use that string but I would like to skip that step if possible...

iDev
  • 1,042
  • 13
  • 19
joels
  • 7,249
  • 11
  • 53
  • 94
  • did u find a solution to this ? – Kong Hantrakool Jul 17 '14 at 09:54
  • 2
    if anyone is seeing this in the debugger, it likely isn't what you think it is. lldb will escape certain characters in strings when displaying AND printing the string. to test, instead of doing `po ` do `po print()`. I lost 3 hours of my life to that oddity. the "\" isn't actually there... – BTRUE Apr 04 '17 at 21:42
  • 1
    @BTRUE ...and you, sir, are a steely-eyed missile man. You just SAVED me 3 hours. Many thanks. – Roy Falk Jul 05 '17 at 13:30
  • Here's my answer with a category on ```AFJSONRequestSerializer```, based on joel's approach: https://stackoverflow.com/a/30802624/1675788 – Dannie P Jun 12 '15 at 12:06

5 Answers5

20

This worked for me

NSDictionary *policy = ....;
NSData *policyData = [NSJSONSerialization dataWithJSONObject:policy options:kNilOptions error:&error];
if(!policyData && error){
    NSLog(@"Error creating JSON: %@", [error localizedDescription]);
    return;
}

//NSJSONSerialization converts a URL string from http://... to http:\/\/... remove the extra escapes
policyStr = [[NSString alloc] initWithData:policyData encoding:NSUTF8StringEncoding];
policyStr = [policyStr stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"];
policyData = [policyStr dataUsingEncoding:NSUTF8StringEncoding];
joels
  • 7,249
  • 11
  • 53
  • 94
  • 1
    This would damage strings like \/\/ smileys. "Here is a backslash followed by slash: \\/" will be replaced with "Here is a backslash followed by \/", which is not what anyone would want. – Lev Walkin Dec 04 '15 at 10:05
  • 3
    @LevWalkin "\/\/" smile will be encoded as "\\/\\/", after replacing "\/" to "/" it will be "'\/\/" again – Alexey Kozhevnikov Mar 02 '16 at 00:56
5

Yeah, this is quite irritating and even more so because it seems there's no "quick" fix to this (i.e. for NSJSONSerialization)

source:
http://www.blogosfera.co.uk/2013/04/nsjsonserialization-serialization-of-a-string-containing-forward-slashes-and-html-is-escaped-incorrectly/
or
NSJSONSerialization serialization of a string containing forward slashes / and HTML is escaped incorrectly


(just shooting in the dark here so bear with me)
If, you're making your own JSON then simply make an NSData object out of a string and send it to the server.
No need to go via NSJSONSerialization.

Something like:

NSString *strPolicy = [info description];
NSData *policyData = [strPolicy dataUsingEncoding:NSUTF8StringEncoding];

i know it won't be so simple but... hm... anyways

Community
  • 1
  • 1
staticVoidMan
  • 19,275
  • 6
  • 69
  • 98
  • Thanks for the links. As for the shot in the dark, I would do that if I was building the json string manually but I use NSJSONSerialization to make building the string much easier. The above was just a simple example for the question. – joels Oct 30 '13 at 15:29
  • yeah, with more variables and parameters to consider, I can understand that NSJSONSerialization is easier. Anyways, if i ever find a solution to this, i'll remember to post back here. – staticVoidMan Oct 31 '13 at 04:51
  • In the end I also just manually constructed the JSON for this one case, in all other cases I use the JSONSerializer. Don't like having to have the app go back through and replace strings when it might axe a valid occurrence of those chars (possible they could occur naturally in a Base64 encoding). – Kendall Helmstetter Gelner Jun 12 '19 at 21:43
5

If your target is >= iOS 13.0, then just add .withoutEscapingSlashes to the options.

Example:

let data = try JSONSerialization.data(withJSONObject: someJSONObject, options: [.prettyPrinted, .withoutEscapingSlashes])

print(String(data: data, encoding: String.Encoding.utf8) ?? "")
Vmark
  • 156
  • 3
  • 6
2

I have tracked this issue for many years, and it is still not fixed. I believe Apple will never fix it for legacy reasons (it will break stuff).

The solution in Swift 4.2:

let fixedString = string.replacingOccurrences(of: "\\/", with: "/")

It will replace all \/ with /, and is safe to do so.

samwize
  • 25,675
  • 15
  • 141
  • 186
  • The only real solution, even ten years later, because Apple are so stupid they don't allow you to do **BOTH** `.prettyPrinted` and `.withoutEscapingSlashes`. Ah well. – Fattie Jul 02 '23 at 22:30
  • @Fattie If you're using `JSONEncoder`, it is configured as OptionSet so you can set to `[.prettyPrinted, .withoutEscapingSlashes]` – samwize Jul 19 '23 at 07:06
  • sam thanks for that, you know, I've never been able to get that to work but based on your comment I will check more carefully!! TY ! – Fattie Jul 19 '23 at 11:27
0

I had this issue and resolved it by instead using the now available JSONEncoder. Illustrated with code:

struct Foozy: Codable {
    let issueString = "Hi \\ lol lol"
}

let foozy = Foozy()

// crashy line
//let json = try JSONSerialization.data(withJSONObject: foozy, options: [])

// working line
let json = try JSONEncoder().encode(foozy)
Codezy
  • 5,540
  • 7
  • 39
  • 48