Как сохранить 128-битный UUID в 16-байтовый ASCII NSString

Я хочу сохранить 128-битный UUID в 16-байтовой строке, которая будет храниться в Core Data как атрибут индекса моего ManagedObject, чтобы обеспечить эффективность вставки и выбора.

Есть ли способ сохранить 128-битный UUID в 16-байтовой строке ASCII? Если есть, как преобразовать между 32-байтовой строкой UUID и 16-байтовой строкой ASCII?

Я попытался сохранить CFUUIDBytes в строку, используя приведенный ниже код, но значение изменилось после создания строки. (если любое значение байта> 127, его значение изменяется в сгенерированной строке)

CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
CFUUIDBytes uuidBytes = CFUUIDGetUUIDBytes(uuidRef);
NSString *utf8String = [NSString stringWithFormat:@"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", 
                            uuidBytes.byte0, uuidBytes.byte1, uuidBytes.byte2,
                            uuidBytes.byte3, uuidBytes.byte4, uuidBytes.byte5,
                            uuidBytes.byte6, uuidBytes.byte7, uuidBytes.byte8,
                            uuidBytes.byte9, uuidBytes.byte10, uuidBytes.byte11,
                            uuidBytes.byte12, uuidBytes.byte13, uuidBytes.byte14,
                            uuidBytes.byte15];

person Cable W    schedule 06.07.2012    source источник
comment
Для хранения 128 бит требуется 16 байтов, но они не могут быть ASCII (или UTF-8), поскольку они двоичные; вам нужно будет использовать как минимум 32 байта.   -  person trojanfoe    schedule 06.07.2012
comment
Спасибо за ваш комментарий! Не могли бы вы подробнее объяснить, почему его нельзя сохранить в ASCII или UTF-8? Собственно, мой тест тоже показывает то, что вы предложили, но я только не знаю, почему.   -  person Cable W    schedule 06.07.2012
comment
Их нельзя хранить в ASCII/UTF-8, потому что процесс их строковой обработки требует, чтобы каждый байт хранился в двух байтах. Возможно, вы сможете использовать двоичную форму в Core Data (я не знаю)?   -  person trojanfoe    schedule 06.07.2012


Ответы (1)


Используйте эту категорию в NSString любезно:

   static unichar x (unsigned int); 

@implementation NSString (TWUUID) 

+ (NSString*) stringWithUniqueId 
{ 
    CFUUIDRef uuid = CFUUIDCreate(NULL); 
    CFUUIDBytes b = CFUUIDGetUUIDBytes(uuid); 
    unichar unichars[22]; 
    unichar* c = unichars; 
    *c++ = x(b.byte0 >> 2); 
    *c++ = x((b.byte0 & 3 << 4) + (b.byte1 >> 4)); 
    *c++ = x((b.byte1 & 15 << 2) + (b.byte2 >> 6)); 
    *c++ = x(b.byte2 & 63); 
    *c++ = x(b.byte3 >> 2); 
    *c++ = x((b.byte3 & 3 << 4) + (b.byte4 >> 4)); 
    *c++ = x((b.byte4 & 15 << 2) + (b.byte5 >> 6)); 
    *c++ = x(b.byte5 & 63); 
    *c++ = x(b.byte6 >> 2); 
    *c++ = x((b.byte6 & 3 << 4) + (b.byte7 >> 4)); 
    *c++ = x((b.byte7 & 15 << 2) + (b.byte8 >> 6)); 
    *c++ = x(b.byte8 & 63); 
    *c++ = x(b.byte9 >> 2); 
    *c++ = x((b.byte9 & 3 << 4) + (b.byte10 >> 4)); 
    *c++ = x((b.byte10 & 15 << 2) + (b.byte11 >> 6)); 
    *c++ = x(b.byte11 & 63); 
    *c++ = x(b.byte12 >> 2); 
    *c++ = x((b.byte12 & 3 << 4) + (b.byte13 >> 4)); 
    *c++ = x((b.byte13 & 15 << 2) + (b.byte14 >> 6)); 
    *c++ = x(b.byte14 & 63); 
    *c++ = x(b.byte15 >> 2); 
    *c = x(b.byte15 & 3); 
    CFRelease(uuid); 
    return [NSString stringWithCharacters: unichars length: 16];
} 
@end

unichar x (unsigned int c)
{
    if (c < 26) return 'a' + c;
    if (c < 52) return 'A' + c - 26;
    if (c < 62) return '0' + c - 52;
    if (c == 62) return '$';
    return '_';
}


...


    NSLog(@"%u", [[NSString stringWithCString:[[NSString stringWithUniqueId] UTF8String] encoding:NSASCIIStringEncoding] length]);
person CodaFi    schedule 06.07.2012
comment
Спасибо. Но использование CFUUIDCreateString() может генерировать только 36-байтовую строку UUID. Поскольку я хотел бы сохранить UUID в качестве основного идентификатора моего объекта Core Date, я хочу, чтобы он был как можно короче (16 байт). - person Cable W; 06.07.2012
comment
Я пробовал, но, кажется, не работает. Можете ли вы привести рабочий пример? рабочий код, я имею в виду. - person Cable W; 06.07.2012
comment
Извините, этот код был дерьмовым. Попробуйте тот, что в моем редактировании, к фактическому сообщению. - person CodaFi; 06.07.2012
comment
Я тоже попробовал это и проверил результат. Но это выглядит хуже, чем код, который я использовал выше. Может быть, я сделал что-то не так. Не могли бы вы проверить свой код и опубликовать рабочий код? Спасибо - person Cable W; 06.07.2012
comment
Это работает, но результат все еще 36 байт NSString. Я хочу 16 байт NSString. Но все равно спасибо! - person Cable W; 06.07.2012
comment
Наконец, удалось сократить эту штуку до 16 байт. Имейте это. - person CodaFi; 06.07.2012
comment
Причина, по которой я не использую NSData, заключается в том, что он сопоставляется с типом BLOB в SQLite (в разделе Core Data), который почти несопоставим и менее эффективен, чем тип TEXT (NSString). Кроме того, тип Integer в SQLite составляет 64 бита, что намного меньше, чем 128 бит UUID. Поэтому NSString, к сожалению, мой единственный выбор. - person Cable W; 06.07.2012
comment
Вы не можете поместить строку в новую кодировку и ожидать меньшего размера той же строки, не урезая саму строку. Минимум, который может быть, это 36 байтов в UTF-8, поэтому здесь используется только длина 16 байтов, чтобы сохранить требуемое пространство. Наконец, этот фактически регистрирует 16 байтов. - person CodaFi; 06.07.2012
comment
извините, мой тест не может преобразовать строку, сгенерированную с использованием вашего метода, обратно в исходные байтовые данные. но большое спасибо - person Cable W; 06.07.2012