简体   繁体   English

Objective-C ARC:使用块作为C ++回调是否正确

[英]Objective-C ARC: is it correct to use a block as C++ callback

I have a App written in C++ and Objective-C. 我有一个用C ++和Objective-C编写的应用程序。 The C++ part receive data from a remote camera and call Objective-C callback(Block) to display. C ++部分从远程摄像机接收数据,然后调用Objective-C回调(块)进行显示。 Objective-C is ARC enabled. Objective-C已启用ARC。

When the display view loaded, I set a block to C++ part, when the data is coming, C++ will call this block to update the display. 当加载显示视图时,我在C ++部分设置了一个块,当数据到来时,C ++将调用此块来更新显示。

The code as follows: 代码如下:

- (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() is a C++ function to set a callback. setDisplayCallback()是用于设置回调的C ++函数。

When the app runs, in the xcode panel shows the app memory usage, and it is always increasing, hours later, the app crashed, I think it is memory leak? 当应用程序运行时,在xcode面板中显示应用程序的内存使用量,并且始终在增加,数小时后,应用程序崩溃了,我认为这是内存泄漏吗?

I have try to comment the code: 我试图注释代码:

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

The memory leak stopped. 内存泄漏已停止。

Question 1 Is there retain cycle to cause this memory leak? 问题1是否有保留周期导致此内存泄漏?

I have try to replace the block code from: 我尝试从以下位置替换代码块:

 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;
 };

to: 至:

 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;
 };

The memory leak problem reduced, but still have. 内存泄漏的问题减少了,但仍然存在。

Question 2 What's the difference between dataWithBytes and dataWithBytesNoCopy ? 问题2 dataWithBytesdataWithBytesNoCopy什么区别?

UPDATE UPDATE

I try to set this single file with no-ARC, and modify the code: 我尝试设置没有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);
}

The memory usage is stable. 内存使用情况稳定。 I'm curious what's the problem in my ARC version code. 我很好奇我的ARC版本代码有什么问题。

In backwards order: 倒序:

  1. The difference between -dataWithBytes... and -dataWithBytesNoCopy... is there in the name. 名称中有-dataWithBytes...-dataWithBytesNoCopy...之间的区别。 Normally, if you create an NSData using a raw byte array, the NSData will copy all the bytes internally so that it knows its underlying data cannot be modified independently (and it can also manage the memory however it wants to). 通常,如果使用原始字节数组创建NSData,则NSData会在内部复制所有字节,以便知道无法独立修改其基础数据(并且还可以根据需要管理内存)。 If you use the ...NoCopy variant, you're telling the NSData to use the buffer you hand it as its storage, and not to allocate any more. 如果使用...NoCopy变体,则是在告诉NSData使用您将其传递给它的缓冲区作为缓冲区,而不要再分配它。 This has the upside of not using any more memory of course (important for larger buffers maybe) but the downside that you need to be a lot more careful about what pointer you hand it and what you do with that pointer afterwards. 当然,这样做的好处是不使用任何更多的内存(也许对于更大的缓冲区来说很重要),但是缺点是您需要更加小心所使用的指针以及指针之后的操作。 If you pass in YES for freeWhenDone as you are doing here, you are telling the NSData to call free() on the pointer when it is itself deallocated. 如果您在此处为freeWhenDone传递YES, freeWhenDone是在告诉NSData自身释放后,在指针上调用free() This assumes it was allocated directly from malloc and effectively transfers ownership of a malloc buffer to the NSData. 这假定它是直接从malloc分配的,并有效地将malloc缓冲区的所有权转移到NSData。

  2. Is there a retain cycle in your code? 您的代码中是否有保留周期? No, there is not an obvious one. 不,没有明显的一个。

So what you're seeing depends on what you mean by "leak", what else is happening in the surrounding code, and what you expect to see. 因此,您所看到的取决于“泄漏”的含义,周围代码中正在发生的其他事情以及希望看到的东西。 What you appear to be doing is taking the bytes from pData , either copying them into an NSData or transferring their ownership to an NSData, and then using that data to create a UIImage , and putting that into a UIImageView . 您似乎正在做的是从pData获取字节,将其复制到NSData或将其所有权转让给NSData,然后使用该数据创建UIImage并将其放入UIImageView How you should handle the memory management of the NSData depends on the ownership of pData , which you don't show. 应该如何处理的内存管理NSData取决于所有权pData ,你不显示。 (Who mallocs it? Who is expected to free it? When?). (谁分配它?谁应该释放它?何时?)。 Creating the UIImage from the image data will use memory of course, but will not "leak" it. 从图像数据创建UIImage当然会使用内存,但不会“泄漏”它。 If you comment that out, then you'll for sure use less memory, but obviously won't get the image. 如果您将其注释掉,则可以肯定会使用更少的内存,但显然不会得到图像。 :) (The NSData itself will be deallocated always just after the -performSelector... is complete, because it goes out of scope afterwards, taking the buffer with it in both your cases.) :)(NSData本身总是在-performSelector...完成之后-performSelector...释放,因为它随后超出范围,在两种情况下都将其-performSelector...缓冲区中。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM