Objective-C ARC:将块用作C ++回调是正确的

时间:2014-05-20 01:32:50

标签: c++ objective-c memory-leaks automatic-ref-counting

我有一个用C ++和Objective-C编写的应用程序。 C ++部分从远程摄像机接收数据并调用Objective-C回调(Block)进行显示。 Objective-C已启用ARC。

当加载显示视图时,我将一个块设置为C ++部分,当数据到来时,C ++将调用此块来更新显示。

代码如下:

- (void)viewDidLoad
{
    __weak CameraVC *weakSelf = self;
    self.callback_func = ^int(int iWidth, int iHeight, int iDataLen, void *pData) {
        NSData *data = [NSData dataWithBytes:pData length:iDataLen];
        [weakSelf performSelectorOnMainThread:@selector(updateDisplayWithData:)
                                   withObject:data waitUntilDone:YES];
        return 0;
    };
    setDisplayCallback(self.callback_func);
}

- (void)updateDisplayWithData:(NSData *)data
{
    self.imageView.image = [UIImage imageWithData:data];
}

setDisplayCallback()是一个用于设置回调的C ++函数。

当应用程序运行时,在xcode面板中显示应用程序内存使用情况,并且它总是在增加,几小时后,应用程序崩溃,我认为是内存泄漏?

我试着评论代码:

// self.imageView.image = [UIImage imageWithData:data];

内存泄漏停止了。

问题1 是否存在导致此内存泄漏的周期?

我试图替换以下代码:

 self.callback_func = ^int(int iWidth, int iHeight, int iDataLen, void *pData) {
    NSData *data = [NSData dataWithBytes:pData length:iDataLen];
    [weakSelf performSelectorOnMainThread:@selector(updateDisplayWithData:)
                               withObject:data waitUntilDone:YES];
    return 0;
 };

为:

 self.callback_func = ^int(int iWidth, int iHeight, int iDataLen, void *pData) {
    NSData *data = [NSData dataWithBytesNoCopy:pData length:iDataLen freeWhenDone:YES];
    [weakSelf performSelectorOnMainThread:@selector(updateDisplayWithData:)
                               withObject:data waitUntilDone:YES];
    return 0;
 };

内存泄漏问题减少了,但仍然存在。

问题2 dataWithBytesdataWithBytesNoCopy之间有什么区别?

更新

我尝试使用no-ARC设置此单个文件,并修改代码:

- (void)viewDidLoad
{
    self.callback_func = ^int(int iWidth, int iHeight, int iDataLen, void *pData) {
        @autoreleasepool {
            NSData *data = [NSData dataWithBytes:pData length:iDataLen];
            [self performSelectorOnMainThread:@selector(updateDisplayWithData:)
                                   withObject:data waitUntilDone:YES];
        }
        return 0;
    };
    setDisplayCallback(self.callback_func);
}

内存使用情况稳定。我很好奇ARC版本代码中的问题是什么。

1 个答案:

答案 0 :(得分:1)

按向后顺序:

  1. -dataWithBytes...-dataWithBytesNoCopy...之间的区别在于名称。通常,如果使用原始字节数组创建NSData,NSData将在内部复制所有字节,以便它知道其基础数据不能独立修改(并且它也可以管理内存,但它想要)。如果您使用...NoCopy变体,则告诉NSData使用您将其作为存储的缓冲区,而不是再分配。这当然没有使用任何更多的内存(对于更大的缓冲区来说很重要),但是你需要更加小心你需要什么指针以及之后用指针做什么。如果你在这里传递的是freeWhenDone的YES,那么你告诉NSData在它自己被解除分配时调用指针上的free()。这假定它是直接从malloc分配的,并有效地将malloc缓冲区的所有权转移到NSData。

  2. 代码中是否有保留周期?不,没有明显的一个。

  3. 因此,您所看到的内容取决于您所说的"泄漏",周围代码中还发生了什么,以及您希望看到的内容。您似乎正在做的是从pData获取字节,将它们复制到NSData或将其所有权转移到NSData,然后使用该数据创建UIImage,并将其放入UIImageView 应如何处理NSData的内存管理取决于您未显示的pData的所有权。 (谁是mallocs呢?谁应该释放它?什么时候?)。从图像数据创建UIImage当然会使用内存,但不会泄漏"它。如果您对此进行评论,那么您肯定会使用更少的内存,但显然无法获得图像。 :)(NSData本身将在-performSelector...完成之后被释放,因为它在之后超出范围,在两种情况下都使用缓冲区。)