Objective c 为什么[NSData字节]可以更改并影响NSData对象本身
假设我有来自另一个人的以下代码:Objective c 为什么[NSData字节]可以更改并影响NSData对象本身,objective-c,Objective C,假设我有来自另一个人的以下代码: -(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]
-(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;
}
STRING1:(NSString*)str1和STRING2:(NSString*)str2之间的-(NSString*)XOR{
NSData*d1=[str1数据使用编码:4];
常量void*b1=[d1字节];
NSData*d2=[str2数据使用编码:4];
常量void*b2=[d2字节];
常数void*b3=b2;
int c=0;
对于(int i=0;i<[d1长度];i++){
*(字节*)b1++^=*(字节*)b3++;
C++;
如果(c==[str2长度]){
c=0;
b3=b2;
}
}
NSString*result=[[NSString alloc]initWithData:d1编码:4];
返回结果;
}
我记得,[NSData bytes]返回const void*
,这意味着指针指向的内容是不可变的。但是,上述功能确实改变了NSData的内容:
之前:
(lldb)po v20
之后:
(lldb)po v20
我很困惑,为什么没有错误?还是我犯了什么错误
更新:
我发现[str1 datausingencode:4]正在返回
nsconcertemutabledata
。似乎是根本原因。但是为什么它返回的是nsconcreteumtabledata
,而不是纯NSData
?我的意思是苹果文档从来没有提到过它?上面的代码是允许的,不是因为幕后有一个nsconcreteumtabledata
,而是因为作者正在将const
指针投射到一个非const
指针。在Objective-C中,在进行强制转换时,可以绕过所有类型和易变性安全
bytes
引用所指向的数据的这种变异是一种可怕的做法,因为您无法确定此NSData
可能对该基础数据缓冲区做出了哪些假设或操作。您应该执行mutableCopy
以获取NSMutableData
,然后使用mutableBytes
或使用replaceBytes…
方法之一
正如mutableBytes
所述:
此[mutableBytes
]属性与bytes
属性类似,但不同。bytes
属性包含指向常量的指针。可以使用bytes
指针读取数据对象管理的数据,但不能修改该数据。但是,如果mutableBytes
属性包含非空指针,则该指针指向可变数据。您可以使用mutableBytes
指针修改数据对象管理的数据
我希望这段代码是从反汇编程序生成的。。。此外,未定义的行为也是未定义的。崩溃或任何运行时错误都是您幸运时的最佳结果。@BryanChen不,我发现的原因是它首先返回NSConcreteModableData。这就是为什么它是可变的。但是为什么可变数据不是NSData呢?苹果文档说它是
NSData
,所以它是NSData
。你只需要知道这些。实施细节仅用于性能优化,您不需要了解和关心它。不要编写任何依赖于它的代码,因为苹果可以在下一次操作系统小更新时更改它,而不必提及它。它很可能返回不同的NSData包装器,具体取决于您使用的编码类型。如果它是这样使用的,它可能应该是可变的。它真的打碎了什么东西,还是你只是好奇?@rmaddy,来自Rhi Rob,谢谢你的回答。由于作者正在将常量指针强制转换为非常量指针,您能否进一步介绍?我这里不清楚。我看到它们都是const void*(Byte*)可以给我任何文档吗?如果你跳转到Xcode中的Byte
的定义,你会发现它只是UInt8
的typedef
,而unsigned char
的typedef
。因此,这是采用v19
,将其强制转换为指向无符号字符的非常量
指针,然后取消引用以更改其指向的字节。