将const字节数组作为输入使用[NSData dataWithBytesNoCopy:... freeWhenDone:NO]是否安全?

时间:2014-01-16 03:48:12

标签: ios objective-c nsdata

我的代码中有一个大型二进制资源,使用bin2c类型程序转换为数组。

以前,我们使用[NSData dataWithBytes:raw length:rawLength]来读取资源(例如)。

这是一个非常大的数组(> 32KB),目前加载和使用此资源的整个过程很慢,所以我尽量节省时间(没有我没有明确分析)此时复制vs noCopy)。

我只是想知道,因为dataWithBytesNoCopy:需要void*而不是const void*,这是否意味着从常量源使用它是不安全的(在这种情况下,它是编译的)进入程序可执行文件)。

我不认为这是NSData开发人员的疏忽,因为initWithBytes:dataWithBytes:都将const void*作为参数 - NSData做了什么(如果有的话)考虑到NSData本身是不可变的,不是const时的输入数据?

我想知道是否可能将参数定义为非const以便与NSMutableData向前兼容?

5 个答案:

答案 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];

    }