Reputation: 9754
Say I have below code from another guy:
-(NSString *)xorBetweenString1:(NSString *)str1 andString2:(NSString *)str2 {
NSData *d1 = [str1 dataUsingEncoding:4];
const void *b1 = [d1 bytes];
NSData *d2 = [str2 dataUsingEncoding:4];
const void *b2 = [d2 bytes];
const void *b3 = b2;
int c = 0;
for (int i = 0; i < [d1 length]; i ++) {
*(Byte *)b1++ ^= *(Byte *)b3++;
c++;
if (c == [str2 length]) {
c = 0;
b3 = b2;
}
}
NSString *result = [[NSString alloc] initWithData:d1 encoding:4];
return result;
}
As I remember, [NSData bytes] returns const void *
, which means the content the pointer points is not mutable. However, above function indeed changes NSData's contents:
before:
(lldb) po v20 <32383a63 663a6461 3a62613a 64313a39 33>
after:
(lldb) po v20 <166c7a31 327a3431 1e362168 30716a69 17>
I am confused, why no errors? Or I made any mistake?
UPDATE:
I found [str1 dataUsingEncoding:4] is returning NSConcreteMutableData
. Seems the root cause. But why it returns NSConcreteMutableData
instead pure NSData
? I mean the apple doc never mentioned it?
Upvotes: 1
Views: 633
Reputation: 438152
The above code is allowed, not because there's a NSConcreteMutableData
behind the scene, but rather simply because the author is casting a const
pointer to a non-const
pointer. In Objective-C, you can bypass all type and mutability safety when you engage in casts.
This mutating of data pointed to by the bytes
reference is a horrible practice because you have no assurances as to what assumptions or actions this NSData
may have made with respect to this underlying data buffer. You should be doing a mutableCopy
to get NSMutableData
and then working with mutableBytes
or using one of the replaceBytes...
methods.
As the mutableBytes
documentation says:
This [
mutableBytes
] property is similar to, but different than thebytes
property. Thebytes
property contains a pointer to a constant. You can use thebytes
pointer to read the data managed by the data object, but you cannot modify that data. However, if themutableBytes
property contains a non-null pointer, this pointer points to mutable data. You can use themutableBytes
pointer to modify the data managed by the data object.
Upvotes: 3