从命名空间生成UUID?

5

尝试基于2个唯一字符串生成客户端ID。 这应该与服务器上生成的相同UUID相同,来自相同的IDs。

使用Javascript,代码如下:

uuidv5(id1 + id2 , uuidv5.DNS);

似乎找不到一种在Swift中生成这个的方法,NSUUID只能从无处生成UUID

NSUUID().uuidString

我正在寻找类似这样的东西:
NSUUID(namespace: id1 + id2).uuidString

编辑

示例:

let sorted = ["5a23dbfb2626b400190998fc", "5pCAvA7h8k9JuErRn"]
let appended = sorted.seperaredStringBy("-")
let result = uuidv5(appended , uuidv5.DNS)

//results:
2522b097-8532-548e-a18b-9366c6511b5e

2
initWithUUIDString:initWithUUIDBytes:方法。现在的问题是,uuidv5(id1 + id2, uuidv5.DNS)究竟是什么意思?请注意,在Swift 3+中,您应该使用UUID而不是提供相同方法的NSUUIDinit(uuidString:))。 - Larme
@Larme 感谢您的快速回复。据我所知,initWithUUID将从UUID字符串生成一个UUID对象。我正在寻找一种方法来附加2个字符串(不是UUID),然后从结果创建一个UUID,该UUID将是唯一的。无论何时何地生成,都将从相同的ID保持不变。 - MCMatan
至少你应该添加一个添加字符串的示例和从中生成UUID的输出,这样就可以进行比较。 - Ahmad F
你可以自己计算SHA1字节。 - Reeonce Zeng
2个回答

13

据我所知,Swift标准库或Foundation框架都没有版本5 UUID的内置方法。

以下是一个可能的版本3和版本5 UUID实现,摘自生成v5 UUID。名称和命名空间是什么?的描述以及RFC 4122中的参考实现。

(已更新为Swift 4及更高版本。)

import Foundation
import CommonCrypto

extension UUID {

    enum UUIDVersion: Int {
        case v3 = 3
        case v5 = 5
    }

    enum UUIDv5NameSpace: String {
        case dns  = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
        case url  = "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
        case oid  = "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
        case x500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
    }

    init(version: UUIDVersion, name: String, nameSpace: UUIDv5NameSpace) {
        // Get UUID bytes from name space:
        var spaceUID = UUID(uuidString: nameSpace.rawValue)!.uuid
        var data = withUnsafePointer(to: &spaceUID) { [count =  MemoryLayout.size(ofValue: spaceUID)] in
            Data(bytes: $0, count: count)
        }

        // Append name string in UTF-8 encoding:
        data.append(contentsOf: name.utf8)

        // Compute digest (MD5 or SHA1, depending on the version):
        var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
        data.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> Void in
            switch version {
            case .v3:
                _ = CC_MD5(ptr.baseAddress, CC_LONG(data.count), &digest)
            case .v5:
                _ = CC_SHA1(ptr.baseAddress, CC_LONG(data.count), &digest)
            }
        }

        // Set version bits:
        digest[6] &= 0x0F
        digest[6] |= UInt8(version.rawValue) << 4
        // Set variant bits:
        digest[8] &= 0x3F
        digest[8] |= 0x80

        // Create UUID from digest:
        self = NSUUID(uuidBytes: digest) as UUID
    }
}

示例1(您的情况):

let uuid = UUID(version: .v5, name: "5a23dbfb2626b400190998fc-5pCAvA7h8k9JuErRn", nameSpace: .dns)
print(uuid) // 2522B097-8532-548E-A18B-9366C6511B5E

例子2(来源于RFC 4122的附录B,经过勘误更正):

let uuid = UUID(version: .v3, name: "www.widgets.com", nameSpace: .dns)
print(uuid) //3D813CBB-47FB-32BA-91DF-831E1593AC29

2
你很棒。谢谢。 - MCMatan
1
变量data的赋值语句如下: var data = withUnsafePointer(to: &spaceUID, { [s = spaceUID] b in return Data(bytes: b, count: MemoryLayout.size(ofValue: s)) }) 在原有代码中,我遇到了“Overlapping accesses to 'spaceUID', but modification requires exclusive access; ; consider copying to a local variable withUnsafePointer”错误。因此,我对代码进行了修改。 - User18474728
@User18474728:你说得对,这是 https://github.com/apple/swift-evolution/blob/master/proposals/0176-enforce-exclusive-access-to-memory.md 的一个后果。我已经更新了代码来解决这个问题和另一个警告。感谢您让我知道。 - Martin R
嗨,有没有 Objective-C 版本? - GoInterface

1

如果有人需要,这是 Objective-C 版本。

+ (CBUUID *)UUIDWithNamespace:(NSString *)namespace name:(NSString *)name version:(int)version
{
    if (namespace.length <= 0 || name == nil  ) { return nil; }
    if (!(version == 3        || version == 5)) { return nil; }
    CBUUID *namespaceUUID = [CBUUID UUIDWithString:namespace];
    if (namespaceUUID == nil) { return nil; }
    NSMutableData *data = [[NSMutableData alloc] init];
    [data appendData:namespaceUUID.data];
    [data appendData:[name dataUsingEncoding:NSUTF8StringEncoding]];
    unsigned char hash[CC_SHA1_DIGEST_LENGTH];
    if (version == 3) {
        CC_MD5(data.bytes, (int)data.length, hash);
    } else if (version == 5) {
        CC_SHA1(data.bytes, (int)data.length, hash);
    }
    unsigned char result[16];
    memcpy(result, hash, 16);
    result[6] &= 0x0F;
    result[6] |= (((unsigned char)version) << 4);
    result[8] &= 0x3F;
    result[8] |= 0x80;
    return [CBUUID UUIDWithData:[NSData dataWithBytes:result length:16]];
}

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