我的代码中有一个大型二进制资源,使用bin2c类型程序转换为数组。
以前,我们使用[NSData dataWithBytes:raw length:rawLength]
来读取资源(例如)。
这是一个非常大的数组(> 32KB),目前加载和使用此资源的整个过程很慢,所以我尽量节省时间(没有我没有明确分析)此时复制vs noCopy)。
我只是想知道,因为dataWithBytesNoCopy:
需要void*
而不是const void*
,这是否意味着从常量源使用它是不安全的(在这种情况下,它是编译的)进入程序可执行文件)。
我不认为这是NSData开发人员的疏忽,因为initWithBytes:
和dataWithBytes:
都将const void*
作为参数 - NSData做了什么(如果有的话)考虑到NSData本身是不可变的,不是const时的输入数据?
我想知道是否可能将参数定义为非const
以便与NSMutableData向前兼容?
答案 0 :(得分:2)
最坏的情况是NSData会复制字节。声明最有可能追溯到过去,如果编译器看到两个具有相同方法名但具有不同类型的声明,则会感到困惑。
答案 1 :(得分:1)
理论上,[NSData dataWithBytesNoCopy:...]映射到CFDataCreateWithBytesNoCopy()或类似的低级函数,其文档描述了它如何处理原始字节:
讨论
此函数从非结构化字节的缓冲区创建不可变CFData对象。除非情况另有说明,否则创建的对象不会将外部缓冲区复制到内部存储区,而是将缓冲区用作其后备存储区。但是,您不应该依赖使用外部缓冲区的对象,因为它可以将缓冲区复制到内部存储区,或者甚至可以完全转储缓冲区并使用其他方法来存储字节。
换句话说,可以复制缓冲区 ,并且不能依赖于对原始缓冲区的更改“传播”到NSData,但这不是问题。原始问题仍然没有答案:它是否会在原地修改原始字节(尽管提示现在可能非常明显)。
更新:
如果情况允许,你可以只加载NSData一次,然后只需将其复制到热循环中(复制很便宜,因为NSData是不可变的并且共享内容)。
static const char *myBytes = "myBytes here...";
static NSData *myData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
myData = [[NSData alloc] initWithBytes:myBytes length:strlen(myBytes)]; // EDIT: still need to copy to be clean
});
for (int i = 0; ; i++) {
NSData *hotLoopData = [myData copy];
NSData *hotLoopData = [[NSData alloc] initWithData:myData];
}
答案 2 :(得分:0)
+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)freeWhenDone
为什么bytes
的类型为void *
而不是const void *
?
Apple Development文档告诉“如果freeWhenDone为YES,则返回的对象获取字节指针的所有权并在解除分配时释放它。”
看看free
函数是如何声明的。
void free(void *);
它取无效*作为参数。
为什么bytes
应为void *
而不是const void *
。
在标题中更新了您的问题。
我认为您不应该担心安全问题,因为用于存储二进制资源的内存似乎不是只读内存。
如果内存未被系统标记为const,则无论如何都可以更改它。
const void *
只是意味着您无法通过实例更改内存,这并不意味着内存是只读的。
一个例子,这里没有崩溃。
在堆栈上创建的内存。
int a = 1 ;
const void * pc = (const void *)&a ;
*(char *)(pc) = 'a' ;
在堆上创建的内存。
void * p = malloc(4) ;
const void * pc = p ;
*(char *)(pc) = 'a' ;
答案 3 :(得分:0)
使用[NSData dataWithBytesNoCopy:... freeWhenDone:NO]和const字节数组作为输入是否安全?
只要您不(或不能)释放存储空间,只要您不更改存储内容,就可以了。 e.g。
static const char* foo = { 0x01, 0x02, 0x03 };
使用安全。
我只是想知道,因为dataWithBytesNoCopy:取一个void *而不是const void *,这是否意味着从常量源使用它是不安全的
只有你把
[NSData dataWithBytesNoCopy: … freeWhenDone:YES]
^^^
在解除分配时,您可以要求对象释放数据这一事实是指针指向void*
而不是const void*
的唯一原因
答案 4 :(得分:0)
下面的代码修复了从服务器转换大量字节数组的问题。
NSString* version = [socketDict objectForKey:@"version"];
NSArray *myBytes = [socketDict objectForKey:@"newFirmware"];
NSUInteger packageLength = myBytes.count;
NSMutableData *data = [[NSMutableData alloc] initWithCapacity:packageLength];
for ( NSString *myByte in myBytes) {
int i = [myByte intValue];
[data appendBytes:&i length:1];
}