无法在Swift中将NSData转换为NSString

10

这是我的函数。首先println正确地将哈希值输出到控制台,但在下一行程序崩溃了。你能帮我吗?

func sha256(string: NSString) -> NSString {
    var data : NSData! = string.dataUsingEncoding(NSUTF8StringEncoding)
    var hash = [UInt8](count: Int(CC_SHA256_DIGEST_LENGTH), repeatedValue: 0)
    CC_SHA256(data.bytes, CC_LONG(data.length), &hash)
    let res = NSData(bytes: hash, length: Int(CC_SHA256_DIGEST_LENGTH))
    println(res)
    let resstr = NSString(data: res, encoding: NSUTF8StringEncoding)
    println(resstr)
    return resstr
}

1
并非所有数据都可以用字符串表示。哈希(SHA-256)可表示的可能性基本上为零。这是因为SHA-256(通常的哈希)的结果是二进制数据。即使在不太可能的情况下,它也不会是“合理”的文本。 - zaph
1个回答

41
let resstr = NSString(data: res, encoding: NSUTF8StringEncoding)

如果数据不是有效的UTF-8序列(这种情况非常常见),则返回nil。接下来的println()会崩溃。

对于任意二进制数据,可能的字符串表示形式可以是十六进制字符串或Base-64编码的字符串。

Base-64编码的字符串可以通过以下方式简单获取

let resstr = res.base64EncodedStringWithOptions(nil)

据我所知,没有内置的方法将二进制数据转换为十六进制字符串。 一种可能的Swift实现(受到许多可用的Objective-C解决方案的启发)是

extension NSData {
    func hexString() -> NSString {
        var str = NSMutableString()
        let bytes = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes), count:self.length)
        for byte in bytes {
            str.appendFormat("%02hhx", byte)
        }
        return str
    }
}

但您可以将其直接集成到哈希方法中,而无需使用中间的NSData对象:

func sha256(string: NSString) -> NSString {
    let data = string.dataUsingEncoding(NSUTF8StringEncoding)!
    var hash = [UInt8](count: Int(CC_SHA256_DIGEST_LENGTH), repeatedValue: 0)
    CC_SHA256(data.bytes, CC_LONG(data.length), &hash)
    let resstr = NSMutableString()
    for byte in hash {
        resstr.appendFormat("%02hhx", byte)
    }
    return resstr
}

我该如何将数据转换为UTF-8?控制台显示的res是“74696c22 2d3233cf c5dc040e 70ec9f5b dbcea3cf 53946368 65bb4382 64c782e5”,这正是我需要的,但你的方法却给出了“dGlsIi0yM8/F3AQOcOyfW9vOo89TlGNoZbtDgmTHguU=”,这是错误的。 - Yury Alexandrov
@ЮрикАлександров: <74696c22 2d3233cf …> 是 NSData 对象的 描述。没有内置的方法可以将 NSData 转换为十六进制字符串,但是如果您搜索“NSData to hex string”,您会找到很多解决方案,例如 https://dev59.com/o3M_5IYBdhLWcg3wmkeu 或者 https://dev59.com/vmsz5IYBdhLWcg3w_NED。 - Martin R
1
@ЮрикАлександров:我已经为您添加了一些Swift代码 :) - Martin R
然后接下来的println()会崩溃。println()不会崩溃。println()可以打印值为nil的可选项。崩溃发生在上一行,因为编译器推断resstr具有类型NSString,这会取消可选项。如果他明确声明resstr具有类型NSString!NSString?,它就不会崩溃。 - newacct
@newacct:好的,我已经单步调试过了,它肯定会在println(resstr)处崩溃。原因可能是初始化程序init(data: NSData, encoding: UInt)不返回可选项,请参见beta 6版本说明中的“Swift不支持通过返回null来失败的对象初始化程序”。- 如果您将赋值更改为let resstr : NSString? = NSString(data: res, encoding: NSUTF8StringEncoding),那么println(resstr)将打印“nil”。 - Martin R
显示剩余2条评论

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