ios - 如何在 Swift 中转换 NSData 和 NSString 表示之间的推送 token ?

标签 ios swift apple-push-notifications

我多年来一直使用以下 Objective C 例程,将 NSData 推送 token 转换为 NSString(供 Web 端推送服务使用),反之,获取 token 的已知 NSString 版本并重新创建NSData 表示。现在,我发现需要完全相同的功能,但在 Swift 中。

dataToHex Objective C 代码本质上使用了 printf 格式化:

- (NSString *)dataToHex:(NSData *)data
{
    NSMutableString *str = [NSMutableString stringWithCapacity:100];
    const unsigned char *p = [data bytes];
    NSUInteger len = [data length];
    for(int i=0; i<len; ++i) {
      [str appendFormat:@"%02.2X", p[i]];
    }
    return str; 
}

反译为:

- (NSData *)hexToData:(NSString *)str 
{
    const char *ptr = [str cStringUsingEncoding:NSASCIIStringEncoding];
    NSUInteger len = [str length]/2;
    NSMutableData *data = [NSMutableData dataWithCapacity:len];
    while(len--) {
        char num[5] = (char[]){ '0', 'x', 0, 0, 0 };
        num[2] = *ptr++;
        num[3] = *ptr++;
        uint8_t n = (uint8_t)strtol(num, NULL, 0);

        [data appendBytes:&n length:1];
    }
    return data;
}

通过“巧妙地”覆盖 ASCII 数组中的两个字节,“0xXX”字符串被转换为一个字节,然后附加到可变数据对象。

现在我正在使用 Swift 编写代码,我需要相同的功能,但没有找到任何帖子包含与上面的 Swift 代码类似的内容。

最佳答案

从 iOS 提供的 NSData 表示转换几乎逐行匹配 Objective C 代码:

func dataToHex(data: NSData) -> String
{
    var str: String = String()
    let p = UnsafePointer<UInt8>(data.bytes)
    let len = data.length

    for var i=0; i<len; ++i {
        str += String(format: "%02.2X", p[i])
    }
    return str
}

然而,给定一个 NSString 对象,转换回 NSData 对象有点困难。如果您在模拟器中进行测试,拥有来自真实设备的字符串 token ,并且需要它来注册服务,则可能需要执行此操作。

我采用的第一种方法尝试复制我之前使用的代码,方法是创建一个包含字符对的字符串,然后调用 strtol :

func hexToData0(str: NSString) -> NSData {
    let len = str.length/2
    var data = NSMutableData(capacity:len)!
    var num: [Int8] = [ 0, 0, 0 ]
    let ptr = str.cStringUsingEncoding(NSUTF8StringEncoding)

    for var i=0; i<len; ++i {
        num[0] = ptr[i*2+0]
        num[1] = ptr[i*2+1]
        var n = UInt8 ( strtol(&num, nil, 16) )

        data.appendBytes(&n, length:1)
    }
    return data;
}

我只是感觉到 strtol有点hack,所以我用NSScanner做了同样的事情大约相同的代码大小,但很可能效率较低:

func hexToData1(str: NSString) -> NSData {
    var data = NSMutableData(capacity: str.length/2)!
    for var i = 0; i<str.length; i+=2 {
        let r = NSRange(location: i, length: 2)
        let s = str.substringWithRange(r)
        let sc = NSScanner(string: s)

        var val: UInt32 = 0
        let ret = sc.scanHexInt(&val)
        if ret {
            var b = UInt8(val)
            data.appendBytes(&b, length: 1)
        } else {
            assert(false, "Yikes!")
        }
    }
    return data
}

然后,我想到我可以在 Swift 中完成这一切,不需要 Darwin 或 Foundation,但要多写几行代码:

// Swift 4
func hexToData(str: String) -> Data {
    let len = str.count/2
    var data = Data(capacity:len)
    let ptr = str.cString(using: String.Encoding.utf8)!

    for i in 0..<len {
        var num: UInt8 = 0
        var multi: UInt8 = 16;
        for j in 0..<2 {
            let c: UInt8 = UInt8(ptr[i*2+j])
            var offset: UInt8 = 0

            switch c {
            case 48...57:   // '0'-'9'
                offset = 48
            case 65...70:   // 'A'-'F'
                offset = 65 - 10         // 10 since 'A' is 10, not 0
            case 97...102:  // 'a'-'f'
                offset = 97 - 10         // 10 since 'a' is 10, not 0
            default:
                assert(false)
            }

            num += (c - offset)*multi
            multi = 1
        }
        data.append(num)
    }
    return data;
}

我正在使用最终的 hexToData在我的代码中。

关于ios - 如何在 Swift 中转换 NSData 和 NSString 表示之间的推送 token ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26346542/

相关文章:

ios - JSONDecoder - "Expected to decode Dictionary<String, Any> but found a string/data instead."

ios - APNs 消息发送到服务器,设备 iOS 上没有通知

ios - 请求 APNs VoIP 通知 (Flutter iOS)

ios - 如何在 App Store 上没有应用程序的情况下在 iOS 上测试 Facebook App Invite

iOS:UITableView 重新加载动画

swift - 需要帮助使用 AVAssetExportSession 导出音频

swift - 如何在字典映射中跳过 nil 键值对

iOS 10 Firebase 通知未在后台显示

iphone - 图书阅读器应用指南建议

objective-c - 停止执行并获得用户在 iPad 应用程序上的选择