2017-09-19 11 views
1

J'utilisais la fonction de hachage sur NSData quand j'ai remarqué que le hachage était le même pour deux contenus de données différents.NSData avec un contenu différent ont le même hachage

C'était mon code:

NSDictionary * d1 = @{@"sums":@[@{@"label":@"Work", @"value":@30}, @{@"label":@"Transport", @"value":@50}, @{@"label":@"Material", @"value":@300}]}; 

    NSData * dd1 = [NSKeyedArchiver archivedDataWithRootObject:d1]; 

    NSDictionary * d2 = @{@"sums":@[@{@"label":@"Work", @"value":@30}, @{@"label":@"Transport", @"value":@50}, @{@"label":@"Material", @"value":@9}]}; 

    NSData * dd2 = [NSKeyedArchiver archivedDataWithRootObject:d2]; 

    NSInteger hashd1 = [dd1 hash]; 
    NSInteger hashd2 = [dd2 hash]; 

La dernière valeur est différente, mais les valeurs de hachage sont les mêmes. Je me demandais comment est le hachage pour NSData calculé en Objective-C car il n'y a pas de directives claires de la docs.

Printing description of hashd1: 
(NSInteger) hashd1 = 211676908 
Printing description of hashd2: 
(NSInteger) hashd2 = 211676908 
Printing description of dd2: 
<62706c69 73743030 d4010203 04050641 42582476 65727369 6f6e5824 6f626a65 63747359 24617263 68697665 72542474 6f701200 0186a0af 10110708 11121820 21222324 2a323334 3c3d3e55 246e756c 6cd3090a 0b0c0e10 574e532e 6b657973 5a4e532e 6f626a65 63747356 24636c61 7373a10d 8002a10f 80038009 5473756d 73d20a0b 1317a314 15168004 800a800d 8010d309 0a0b191c 10a21a1b 80058006 a21d1e80 07800880 09556c61 62656c55 76616c75 6554576f 726b101e d2252627 285a2463 6c617373 6e616d65 5824636c 61737365 735c4e53 44696374 696f6e61 7279a227 29584e53 4f626a65 6374d309 0a0b2b2e 10a21a1b 80058006 a22f3080 0b800c80 09595472 616e7370 6f727410 32d3090a 0b353810 a21a1b80 058006a2 393a800e 800f8009 584d6174 65726961 6c1205f5 e100d225 263f4057 4e534172 726179a2 3f295f10 0f4e534b 65796564 41726368 69766572 d1434454 726f6f74 80010008 0011001a 0023002d 00320037 004b0051 00580060 006b0072 00740076 0078007a 007c0081 0086008a 008c008e 00900092 0099009c 009e00a0 00a300a5 00a700a9 00af00b5 00ba00bc 00c100cc 00d500e2 00e500ee 00f500f8 00fa00fc 00ff0101 01030105 010f0111 0118011b 011d011f 01220124 01260128 01310136 013b0143 01460158 015b0160 00000000 00000201 00000000 00000045 00000000 00000000 00000000 00000162> 
Printing description of dd1: 
<62706c69 73743030 d4010203 04050641 42582476 65727369 6f6e5824 6f626a65 63747359 24617263 68697665 72542474 6f701200 0186a0af 10110708 11121820 21222324 2a323334 3c3d3e55 246e756c 6cd3090a 0b0c0e10 574e532e 6b657973 5a4e532e 6f626a65 63747356 24636c61 7373a10d 8002a10f 80038009 5473756d 73d20a0b 1317a314 15168004 800a800d 8010d309 0a0b191c 10a21a1b 80058006 a21d1e80 07800880 09556c61 62656c55 76616c75 6554576f 726b101e d2252627 285a2463 6c617373 6e616d65 5824636c 61737365 735c4e53 44696374 696f6e61 7279a227 29584e53 4f626a65 6374d309 0a0b2b2e 10a21a1b 80058006 a22f3080 0b800c80 09595472 616e7370 6f727410 32d3090a 0b353810 a21a1b80 058006a2 393a800e 800f8009 584d6174 65726961 6c11012c d225263f 40574e53 41727261 79a23f29 5f100f4e 534b6579 65644172 63686976 6572d143 4454726f 6f748001 00080011 001a0023 002d0032 0037004b 00510058 0060006b 00720074 00760078 007a007c 00810086 008a008c 008e0090 00920099 009c009e 00a000a3 00a500a7 00a900af 00b500ba 00bc00c1 00cc00d5 00e200e5 00ee00f5 00f800fa 00fc00ff 01010103 0105010f 01110118 011b011d 011f0122 01240126 01280131 01340139 01410144 01560159 015e0000 00000000 02010000 00000000 00450000 00000000 00000000 00000000 0160> 

même la longueur d'octet est différent

(lldb) po [dd1 length] 
522 

(lldb) po [dd2 length] 
524 
+0

La valeur de hachage n'a pas besoin d'être unique. En fait, la valeur de hachage pourrait être la même pour toutes les instances. Bien sûr, cela rendrait les choses comme les dictionnaires beaucoup moins efficaces. La seule exigence pour 'hash' est qu'il doit être le même pour deux objets qui retournent' YES' pour 'isEqual:'. – rmaddy

Répondre

1

Il est un détail de la mise en œuvre de NSData, mais il utilise seulement les 80 premiers octets de données pour calculer le hachage, à savoir: https://opensource.apple.com/source/CF/CF-635.21/CFData.c:

static CFHashCode __CFDataHash(CFTypeRef cf) { 
    CFDataRef data = (CFDataRef)cf; 
    return CFHashBytes((uint8_t *)CFDataGetBytePtr(data), __CFMin(__CFDataLength(data), 80)); 
} 

L'archiveur à clé ajoute suffisamment de préambule pour que les deux résultats soient les mêmes jusqu'à cette longueur.

pourraient vous intéresser les détails supplémentaires disponibles à How does NSData's implementation of the hash method work?