Swift base64 解码返回 nil

Posted

技术标签:

【中文标题】Swift base64 解码返回 nil【英文标题】:Swift base64 decoding returns nil 【发布时间】:2016-07-21 17:34:20 【问题描述】:

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

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

不幸的是,变量 decodedData 的值为 nil

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

【问题讨论】:

您尝试过基本选项吗? let decodedData=NSData(base64EncodedString: encodedImageData, options: NSDataBase64EncodingOptions()) 【参考方案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())

【讨论】:

【参考方案2】:

特殊字符会造成问题,但有趣的是,如果我们使用 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

【讨论】:

【参考方案3】:

检查您的 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
    


【讨论】:

【参考方案4】:

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

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

更新: 如 cmets 所述,最好先检查字符串长度是否已经是 4 的倍数。如果 encoded64 具有您的 base64 字符串并且它不是常量,您可以执行以下操作:

斯威夫特 2

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

斯威夫特 3

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

斯威夫特 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 在这里,我向 OP 解释为什么 base64 解码可能会失败。当然,先检查一下你的字符串长度是否已经是 4 的倍数也不错。我借此机会更新到 swift 3。 我最终使用:encoded64 = encoded64.padding(toLength: encoded64.characters.count + (4 - remainder) % 4, withPad: "=", startingAt: 0) 没有if @Mbt925 我已经用另一行版本更新了答案,考虑到长度可能已经是 4 的倍数。 用“=”填充目前似乎被破坏了。我建议用“A”填充,这确实有效。已经提交了一个错误。【参考方案5】:

(斯威夫特 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
    

【讨论】:

【参考方案6】:

另一个单行版本:

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

【讨论】:

【参考方案7】:

当字符数能被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)
  

【讨论】:

以上是关于Swift base64 解码返回 nil的主要内容,如果未能解决你的问题,请参考以下文章

将base64URL解码为base64 - Swift

如何从 Web 获取 base64 并在 Swift 中解码?

Swift 中的 Base64 编码不会在 Android 中解码

Swift Decodable - 如何解码经过 base64 编码的嵌套 JSON

无法在iOS swift中将base64string解码为uiimage,但在android中工作正常[重复]

Base64 解码 - 不正确的字符串长度