Swift base64 解码返回 nil。

21

我正在尝试使用以下代码在Swift中将base64字符串解码成图像:

let decodedData=NSData(base64EncodedString: encodedImageData, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)

不幸的是,变量decodedData最终的值为nil。

通过代码调试,我验证了变量encodedImageData不是nil,并且是正确的编码图像数据(使用在线base64转图像转换器进行验证)。可能导致我的问题的原因是什么?


你试过基本选项了吗?let decodedData=NSData(base64EncodedString: encodedImageData, options: NSDataBase64EncodingOptions()) - Eric Aya
8个回答

57

这种方法需要使用“=”进行填充,字符串长度必须是4的倍数。

在某些base64实现中,解码时不需要填充字符,因为可以计算出缺少的字节数。但在Fundation的实现中,填充是强制性的。

更新: 如评论中所述,最好先检查字符串长度是否已经是4的倍数。如果encoded64包含您的base64字符串并且它不是一个常量,则可以执行以下操作:

Swift 2

let remainder = encoded64.characters.count % 4
if remainder > 0 {
    encoded64 = encoded64.stringByPaddingToLength(encoded64.characters.count + 4 - remainder,
                                                  withPad: "=",
                                                  startingAt: 0)
}

Swift 3

let remainder = encoded64.characters.count % 4
if remainder > 0 {
    encoded64 = encoded64.padding(toLength: encoded64.characters.count + 4 - remainder,
                                  withPad: "=",
                                  startingAt: 0)
}

Swift 4

let remainder = encoded64.count % 4
if remainder > 0 {
    encoded64 = encoded64.padding(toLength: encoded64.count + 4 - remainder,
                                  withPad: "=",
                                  startingAt: 0)
}

更新为一行代码版本:

当字符串长度已经是4的倍数时,您可以使用以下一行代码版本返回相同的字符串:

encoded64.padding(toLength: ((encoded64.count+3)/4)*4,
                  withPad: "=",
                  startingAt: 0)

对于字符串长度已经是4的倍数的情况,你的代码会添加四个不必要的“=”! - Mbt925
@Mbt925 在这里我正在向OP解释为什么base64解码可能会失败。当然,首先检查您的字符串长度是否已经是4的倍数并不是一个坏主意。我借此机会更新到Swift 3。 - jlasierra
最终我使用了以下代码:encoded64 = encoded64.padding(toLength: encoded64.characters.count + (4 - remainder) % 4, withPad: "=", startingAt: 0),没有用到 if - Mbt925
@Mbt925 我已经更新了答案,加入了另一种只需一行代码的版本,考虑到长度可能已经是4的倍数。 - jlasierra
@DanielKanaan,请注意,'A'是实际数据,因此如果您用它来填充,您的输出将会多出一到两个字节为0。 - jlasierra
显示剩余9条评论

5

当字符数量可被4整除时,需要避免填充。

private func base64PaddingWithEqual(encoded64: String) -> String {
  let remainder = encoded64.characters.count % 4
  if remainder == 0 {
    return encoded64
  } else {
    // padding with equal
    let newLength = encoded64.characters.count + (4 - remainder)
    return encoded64.stringByPaddingToLength(newLength, withString: "=", startingAtIndex: 0)
  }
}

4

(Swift 3) 我曾经遇到过这种情况,尝试使用base64编码的字符串获取数据时,当我使用这行代码时会返回nil:

let imageData = Data(base64Encoded: strBase64, options: .ignoreUnknownCharacters)

尝试对字符串进行填充,但并没有太成功。

以下是我用过的方法:

func imageForBase64String(_ strBase64: String) -> UIImage? {

    do{
        let imageData = try Data(contentsOf: URL(string: strBase64)!)
        let image = UIImage(data: imageData)
        return image!
    }
    catch{
        return nil
    }
}

1
检查您的decodedData变量内容,查找此前缀"data:image/png;base64",我遇到了这个问题,并注意到我的String base64有这样的前缀,所以我采用了这种方法并且它起作用了。
extension String {
func getImageFromBase64() -> UIImage? {
    guard let url = URL(string: self) else {
        return nil
    }
    do {
        let data = try Data(contentsOf: url)
        return UIImage(data: data)
    } catch {
        return nil
    }

}

}


1
这对我很有帮助:

extension String {
    func fromBase64() -> String? {
        guard let data = Data(base64Encoded: self.replacingOccurrences(of: "_", with: "="), options: Data.Base64DecodingOptions(rawValue: 0)) else {
            return nil
        }

        return String(data: data, encoding: .utf8)
    }
}

使用方法:

print(base64EncodedString.fromBase64())

0

您可以使用此扩展程序来确保字符串具有正确的长度,以便使用Foundation进行解码(可被4整除):

extension String {
    var paddedForBase64Decoding: String {
        appending(String(repeating: "=", count: (4 - count % 4) % 4))
    }
}

使用方法:

Data(base64Encoded: base64String.paddedForBase64Decoding)

0

另一种单行版本:

let length = encoded64.characters.count
encoded64 = encoded64.padding(toLength: length + (4 - length % 4) % 4, withPad: "=", startingAt: 0)

0

在处理特殊字符时可能会出现问题,但有趣的是,如果我们使用NSDataNSString,那么它就可以正常工作。

static func decodeBase64(input: String)->String{
        let base64Decoded = NSData(base64Encoded: input, options:   NSData.Base64DecodingOptions(rawValue: 0))
            .map({ NSString(data: $0 as Data, encoding: String.Encoding.utf8.rawValue) })

        return base64Decoded!! as String
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接