[英]Objective-C ARC: is it correct to use a block as C++ callback
我有一个用C ++和Objective-C编写的应用程序。 C ++部分从远程摄像机接收数据,然后调用Objective-C回调(块)进行显示。 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 dataWithBytes
和dataWithBytesNoCopy
什么区别?
UPDATE
我尝试设置没有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版本代码有什么问题。
倒序:
名称中有-dataWithBytes...
和-dataWithBytesNoCopy...
之间的区别。 通常,如果使用原始字节数组创建NSData,则NSData会在内部复制所有字节,以便知道无法独立修改其基础数据(并且还可以根据需要管理内存)。 如果使用...NoCopy
变体,则是在告诉NSData使用您将其传递给它的缓冲区作为缓冲区,而不要再分配它。 当然,这样做的好处是不使用任何更多的内存(也许对于更大的缓冲区来说很重要),但是缺点是您需要更加小心所使用的指针以及指针之后的操作。 如果您在此处为freeWhenDone
传递YES, freeWhenDone
是在告诉NSData自身释放后,在指针上调用free()
。 这假定它是直接从malloc
分配的,并有效地将malloc缓冲区的所有权转移到NSData。
您的代码中是否有保留周期? 不,没有明显的一个。
因此,您所看到的取决于“泄漏”的含义,周围代码中正在发生的其他事情以及希望看到的东西。 您似乎正在做的是从pData
获取字节,将其复制到NSData或将其所有权转让给NSData,然后使用该数据创建UIImage
并将其放入UIImageView
。 你应该如何处理的内存管理NSData
取决于所有权pData
,你不显示。 (谁分配它?谁应该释放它?何时?)。 从图像数据创建UIImage当然会使用内存,但不会“泄漏”它。 如果您将其注释掉,则可以肯定会使用更少的内存,但显然不会得到图像。 :)(NSData本身总是在-performSelector...
完成之后-performSelector...
释放,因为它随后超出范围,在两种情况下都将其-performSelector...
缓冲区中。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.