9

I'm communicating with a server in Swift retrieving image data. The incoming data is encoded as a base64 string. I am able to correctly receive and display the encoded strings. When I go to use the NSData class to decode the string back to binary data and display...

println(NSData(base64EncodedString: imageString, options: NSDataBase64DecodingOptions(0)))

The output is

nil
nil
nil
nil
nil
nil

One for each of the images received.

I've also tried

println(NSData(base64EncodedString: imageString, options: nil))

and the same results. Is there anything I am missing along the way?? I would put the image strings up but they are massively long...

Freestyle076
  • 1,548
  • 19
  • 36
  • Could you share the base64 string for the image that you are working with? It would be a lot easier to tell you where the point of failure is that way. – Clay McIlrath Jan 15 '15 at 00:21

4 Answers4

21

For others that may be having this issue, make sure your Base64 encoded string has a length divisible by 4 (= should be used to pad the length).

See this StackOverflow answer here: https://stackoverflow.com/a/36366421/330494

Community
  • 1
  • 1
Barlow Tucker
  • 6,229
  • 3
  • 36
  • 42
11

Try to use IgnoreUnknownCharacters option.

Or try to use initWithBase64EncodedString from NSDataAdditions

Mark Pervovskiy
  • 1,123
  • 11
  • 18
4

This can also happen if the input is so-called "URL Safe" Base64 data. This data has the + symbol replaced by the - symbol, and the / symbol replaced by the _ symbol.

Fortunately it's straightforward to convert it:

inputString = [[inputString stringByReplacingOccurrencesOfString:@"-" withString:@"+"] stringByReplacingOccurrencesOfString:@"_" withString:@"/"];

A full list of variants is available on Wikipedia.

Frank Schmitt
  • 25,648
  • 10
  • 58
  • 70
4

Based on Frank Schmitt's and Barlow Tucker's answers I've created an extension to Data to better handle base64 encoding:

extension Data {
    static func decodeUrlSafeBase64(_ value: String) throws -> Data {
        var stringtoDecode: String = value.replacingOccurrences(of: "-", with: "+")
        stringtoDecode = stringtoDecode.replacingOccurrences(of: "_", with: "/")
        switch (stringtoDecode.utf8.count % 4) {
            case 2:
                stringtoDecode += "=="
            case 3:
                stringtoDecode += "="
            default:
                break
        }
        guard let data = Data(base64Encoded: stringtoDecode, options: [.ignoreUnknownCharacters]) else {
            throw NSError(domain: "decodeUrlSafeBase64", code: 1,
                        userInfo: [NSLocalizedDescriptionKey: "Can't decode base64 string"])
        }
        return data
    }
}

so in your code, you can use it like this:

let baseEncodeText = "(.....)" //your base64 encoded string
let data = try Data.decodeUrlSafeBase64(baseEncodeText)
Maciej Gad
  • 1,701
  • 16
  • 21
  • 1
    Sorry to hear that, I’m using this code in my app and it is working fine, so maybe your Base64 string is malformed, you can check it online i.e. https://www.base64decode.org/ – Maciej Gad Feb 03 '20 at 11:55
  • Yes you are correct, or, actually, my base64 string had a header.payload.signature which fails when creating Data(…) So if I just extract the payload part then it works :-) – StackUnderflow Feb 03 '20 at 20:41