Search code examples
nsstringswiftnsdata

Can't convert NSData to NSString in swift


This is my function. First println print correct hash to console but in the next row program crashes. Can you help me?

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
}

Solution

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

    returns nil if the data does not represent a valid UTF-8 sequence (which is very likely). Then the following println() crashes.

    A possible string representation for arbitrary binary data would be a hex string or a Base-64 encoded string.

    A Base-64 encoded string can simply be obtained with

    let resstr = res.base64EncodedStringWithOptions(nil)
    

    There is (as far as I know) no built-in method to convert binary data to a hex string. A possible implementation in Swift (inspired by the lots of available Objective-C solutions) is

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

    But you could integrate that into your hash method directly, without using an intermediate NSData object:

    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
    }