Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macos 如何将NSData转换为NSString十六进制字符串?_Macos_Cocoa - Fatal编程技术网

Macos 如何将NSData转换为NSString十六进制字符串?

Macos 如何将NSData转换为NSString十六进制字符串?,macos,cocoa,Macos,Cocoa,当我在NSData对象上调用-description时,我会看到NSData对象字节的十六进制字符串,如: <f6e7cd28 0fc5b5d4 88f8394b af216506 bc1bba86 4d5b483d> 我想将数据减去lt/gt引号后的表示形式转换成内存中的NSString,这样我就可以使用它了。。我不希望调用-[NSData description],然后只修剪lt/gt引号,因为我认为这不是NSData公共接口的一个保证方面,将来可能会发生变化 除了调用-des

当我在NSData对象上调用-description时,我会看到NSData对象字节的十六进制字符串,如:

<f6e7cd28 0fc5b5d4 88f8394b af216506 bc1bba86 4d5b483d>
我想将数据减去lt/gt引号后的表示形式转换成内存中的NSString,这样我就可以使用它了。。我不希望调用-[NSData description],然后只修剪lt/gt引号,因为我认为这不是NSData公共接口的一个保证方面,将来可能会发生变化

除了调用-description之外,将NSData对象的这种表示形式转换为NSString对象的最简单方法是什么?

请记住,任何Stringformat:。。。对于大数据,解决方案将非常缓慢

NSData *data = ...;
NSUInteger capacity = data.length * 2;
NSMutableString *sbuf = [NSMutableString stringWithCapacity:capacity];
const unsigned char *buf = data.bytes;
NSInteger i;
for (i=0; i<data.length; ++i) {
  [sbuf appendFormat:@"%02X", (NSUInteger)buf[i]];
}
如果您需要更高性能的产品,请尝试以下方法:

static inline char itoh(int i) {
    if (i > 9) return 'A' + (i - 10);
    return '0' + i;
}

NSString * NSDataToHex(NSData *data) {
    NSUInteger i, len;
    unsigned char *buf, *bytes;

    len = data.length;
    bytes = (unsigned char*)data.bytes;
    buf = malloc(len*2);

    for (i=0; i<len; i++) {
        buf[i*2] = itoh((bytes[i] >> 4) & 0xF);
        buf[i*2+1] = itoh(bytes[i] & 0xF);
    }

    return [[NSString alloc] initWithBytesNoCopy:buf
                                          length:len*2
                                        encoding:NSASCIIStringEncoding
                                    freeWhenDone:YES];
}
Swift 4.2版本

extension Data {

    var hexString: String? {
        return withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
            let charA = UInt8(UnicodeScalar("a").value)
            let char0 = UInt8(UnicodeScalar("0").value)

            func itoh(_ value: UInt8) -> UInt8 {
                return (value > 9) ? (charA + value - 10) : (char0 + value)
            }

            let hexLen = count * 2
            let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: hexLen)

            for i in 0 ..< count {
                ptr[i*2] = itoh((bytes[i] >> 4) & 0xF)
                ptr[i*2+1] = itoh(bytes[i] & 0xF)
            }

            return String(bytesNoCopy: ptr,
                               length: hexLen,
                             encoding: .utf8,
                         freeWhenDone: true)
        }
    }
}

遗憾的是,没有内置的方法从NSData生成十六进制,但这很容易自己完成。简单的方法是将连续的字节传递到sprintf%02x中,然后将这些字节累积到NSMutableString中。一种更快的方法是构建一个查找表,将4位映射到一个十六进制字符中,然后将连续的nybles传递到该表中。

虽然这可能不是最有效的方法,但如果您是为了调试而这样做的,SSCrypto在NSData上有一个类别,其中包含两种方法,一种用于创建原始字节值的NSString,另一种用于显示其更漂亮的表示形式

我同意不调用描述的解决方案,该解决方案将保留用于调试,因此这是一个很好的观点和问题:

最简单的解决方案是循环NSData的字节并从中构造NSString。使用[yourData bytes]访问字节,并将字符串构建为NSMutableString

下面是一个使用NSData类别实现此功能的示例

@interface NSData(Hex)
-(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces;
@end

@implementation NSData(Hex)
-(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces
{
    const unsigned char* bytes = (const unsigned char*)[self bytes];
    NSUInteger nbBytes = [self length];
    //If spaces is true, insert a space every this many input bytes (twice this many output characters).
    static const NSUInteger spaceEveryThisManyBytes = 4UL;
    //If spaces is true, insert a line-break instead of a space every this many spaces.
    static const NSUInteger lineBreakEveryThisManySpaces = 4UL;
    const NSUInteger lineBreakEveryThisManyBytes = spaceEveryThisManyBytes * lineBreakEveryThisManySpaces;
    NSUInteger strLen = 2*nbBytes + (spaces ? nbBytes/spaceEveryThisManyBytes : 0);

    NSMutableString* hex = [[NSMutableString alloc] initWithCapacity:strLen];
    for(NSUInteger i=0; i<nbBytes; ) {
        [hex appendFormat:@"%02X", bytes[i]];
        //We need to increment here so that the every-n-bytes computations are right.
        ++i;

        if (spaces) {
            if (i % lineBreakEveryThisManyBytes == 0) [hex appendString:@"\n"];
            else if (i % spaceEveryThisManyBytes == 0) [hex appendString:@" "];
        }
    }
    return [hex autorelease];
}
@end

我最喜欢@Erik_Aigner的答案。我只是对它进行了一些重构:

NSData *data = [NSMutableData dataWithBytes:"acani" length:5];
NSUInteger dataLength = [data length];
NSMutableString *string = [NSMutableString stringWithCapacity:dataLength*2];
const unsigned char *dataBytes = [data bytes];
for (NSInteger idx = 0; idx < dataLength; ++idx) {
    [string appendFormat:@"%02x", dataBytes[idx]];
}

在Swift中,可以创建扩展名

extension NSData {

    func toHexString() -> String {

        var hexString: String = ""
        let dataBytes =  UnsafePointer<CUnsignedChar>(self.bytes)

        for (var i: Int=0; i<self.length; ++i) {
            hexString +=  String(format: "%02X", dataBytes[i])
        }

        return hexString
    }
}

看到注释中有一个Swift 1.2代码段,下面是Swift 2版本,因为C风格的for循环现在已被弃用。 有麻省理工许可证和两个简单的单元测试

以下是为方便您而编写的代码:

import Foundation

extension NSData {
  var hexString: String {
    let pointer = UnsafePointer<UInt8>(bytes)
    let array = getByteArray(pointer)

    return array.reduce("") { (result, byte) -> String in
      result.stringByAppendingString(String(format: "%02x", byte))
    }
  }

  private func getByteArray(pointer: UnsafePointer<UInt8>) -> [UInt8] {
    let buffer = UnsafeBufferPointer<UInt8>(start: pointer, count: length)

    return [UInt8](buffer)
  }
}

只是想补充一点,@PassKits的方法可以非常优雅地使用swift3编写,因为现在的数据是一个集合

extension Data { 
    var hex: String {
        var hexString = ""
        for byte in self {
            hexString += String(format: "%02X", byte)
        }

        return hexString
    }
}
或者

extension Data {
    var hex: String {
        return self.map { b in String(format: "%02X", b) }.joined()
    }
}
甚至

extension Data {
    var hex: String {
        return self.reduce("") { string, byte in
            string + String(format: "%02X", byte)
        }
    }
}

假设您已经设置了:

NSData *myData = ...;
简单解决方案:

NSString *strData = [[NSString alloc]initWithData:myData encoding:NSUTF8StringEncoding];
NSLog(@"%@",strData);

那么,为什么不描述呢?真奇怪。怀疑我会学到一些东西。@Steven:description的输出可能会随着系统版本的不同而变化。例如,[NSDate description]在Lion之前被记录为返回一个字符串,其格式与-[NSDate initWithString:]所需的格式完全相同;这一保证不再作出。这里的简要讨论:description应该仅用于调试目的,因为您不能保证description方法返回的值在将来的版本中不会更改,即使不太可能。例如,没有什么告诉你,苹果某一天不会决定,如果[NStaseString ]>200,那么由描述返回的字符串将被剪辑在中间…或者类似的东西。这就是为什么依赖于描述返回的内容来进行调试/日志记录之外的任何事情可能不是一个好的实践。谢谢我必须承认,我为自己的调试目的提供了自定义描述。我编写了一个NSData到十六进制NSString类别,您可以在这里找到:它类似于AliSoftware的答案。无需使用sprintf;NSMutableString具有appendFormat:。挑剔:如果要匹配描述,则需要%02x,而不是%02x。区别在于小写和大写。很好的代码片段。我在这里做了一些小的修改,使它成为gist:当我使用这个解决方案时,十六进制值90显示为ffffff90。怎么回事?您的0x90输入值可能是有符号整数,而不是无符号整数?解释符号位传播,以及你得到的表示,看起来像2的补码十六进制形式?你的确切代码是什么?我相信var p=unsafemeutablepointer.alloclength*2可以让p=。。。通过Swift 2编译器警告这是值得来到这里只是为了了解StringbytesNoCopy:length:encoding:。这方面的性能非常好…从中学习了一些东西。如果您是使用Realm的开发人员,您可以使用它从密钥链获取加密密钥。计算属性可能更适合Swift样式
NSData *myData = ...;
NSString *strData = [[NSString alloc]initWithData:myData encoding:NSUTF8StringEncoding];
NSLog(@"%@",strData);