Swift NSData from base64encoded string returns nil
Asked Answered
S

5

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...

Shouldst answered 14/1, 2015 at 23:41 Comment(1)
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.Armipotent
B
11

Try to use IgnoreUnknownCharacters option.

Or try to use initWithBase64EncodedString from NSDataAdditions

Billybillycock answered 15/1, 2015 at 0:7 Comment(3)
IgnoreUnknownCharacters option did the trick! Thanks! Any tips as to what was wrong?Shouldst
Maybe you have leading or trailing spaces or some invisible characters in your string.Billybillycock
Oh yes, in our application that is likely. That's gotta be it. Thanks!Shouldst
O
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://mcmap.net/q/593794/-swift-base64-decoding-returns-nil

Olav answered 23/6, 2016 at 16:28 Comment(0)
B
11

Try to use IgnoreUnknownCharacters option.

Or try to use initWithBase64EncodedString from NSDataAdditions

Billybillycock answered 15/1, 2015 at 0:7 Comment(3)
IgnoreUnknownCharacters option did the trick! Thanks! Any tips as to what was wrong?Shouldst
Maybe you have leading or trailing spaces or some invisible characters in your string.Billybillycock
Oh yes, in our application that is likely. That's gotta be it. Thanks!Shouldst
G
5

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)
Gerfen answered 10/9, 2019 at 11:36 Comment(2)
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. base64decode.orgGerfen
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 :-)Exeter
T
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.

Torry answered 27/4, 2017 at 3:13 Comment(0)
V
0

To ensure that the length of the Base64 string is a multiple of 4 characters, use the following function. This function pads the string with '=' characters to achieve the desired fixed length. It's recommended to apply this method before decoding the Base64 string.

extension String {
    var paddedBase64String: Self {
        let offset = count % 4
        guard offset != 0 else { return self }
        return padding(toLength: count + 4 - offset, withPad: "=", startingAt: 0)
    }
}

Usage example:

// Ensure the Base64 string has a fixed-length format
let paddedBase64String = base64String.paddedBase64String

After padding the Base64 string, use paddedBase64String for decoding purposes to ensure consistent behavior.

Vange answered 13/4, 2024 at 2:55 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.