我正在使用CGDataProviderCreateWithData(最终)从malloced字节数组创建一个UIImage。我像这样调用CGDataProviderCreateWithData:
provider = CGDataProviderCreateWithData(NULL, dataPtr, dataLen, callbackFunc);
其中
dataPtr是以前用于图像的malloced数据字节数组, dataLen是dataPtr数组中的字节数,和 callbackFunc如CGDataProviderCreateWithData文档中所述:
void callbackFunc(void *info, const void *data, size_t size);
当数据提供程序被释放时调用回调函数,所以我可以在那里释放()dataPtr,但我可能想继续使用它(dataPtr),并在稍后阶段释放它。这段代码将被多次调用,流程将类似于:
所以1..6可以多次执行。我不希望dataPtr在程序的整个执行过程中徘徊(并且它的大小可能会发生变化),所以我想在必要时使用malloc / free。
问题是我无法在CGDataProviderCreateWithData的回调中释放(dataPtr),因为我仍然想要使用它,所以我想在一段时间之后释放它 - 我不能释放它直到我知道它数据提供者不再需要它(据我所知,CGDataProviderCreateWithData使用我传递的数组,它不需要复制)。
我不能做上面的(1)直到我知道可以释放和重新malloc dataPtr,所以我真正想做的是阻止等待数据提供者被释放(好吧,我想知道我是否应该重新输入1..6代码块,在数据提供程序被释放之前我无法做到这一点。它将是 - 我创建数据提供者,创建图像并立即显示它并释放数据提供者。问题是数据提供程序在UIImage发布并完成后才会实际发布。
我是Objective-c和iOS的新手。我错过了一些明显的东西吗?
答案 0 :(得分:1)
如果你malloc
提供者数据的内存,你真的想在回调中free
。不要试图以任何方式试图规避这一点。它太容易泄漏,容易受到简单的内存问题的影响。
话虽如此,有两个简单的解决方案可以解决您的问题。之一:
制作您自己要与提供商分开管理的数据的副本;或
使用void *
再现(例如CGDataProvider
),而不是使用CFData
方法的CGDataProviderCreateWithCFData
再现,然后您可以保留自己的强引用对于此数据对象(或者如果在非ARC代码中,请执行您自己的retain
数据对象)。在解决所有强引用之前,不会取消分配对象(或者,在非ARC代码中,所有手动retain
调用都通过相应的release
或autorelease
调用解析。
使用这两种方法之一,您可以继续让CGProviderRef
按照自己的意愿管理内存,但您也可以继续使用数据对象。
答案 1 :(得分:0)
我也遇到了类似的问题。我想使用CGImageCreateWithJPEGDataProvider,因此使用CGDataProviderRef和malloc'd字节数组。在创建数据提供程序参考之后尝试释放字节数组时,我遇到了同样的问题。 之所以会发生这种情况,是因为数据提供程序引用接管了字节数组的所有权,因此只有在完成后才能通过引用释放它。 我同意@TheBlack的意见,如果您需要其他地方的数据,请复制它。
答案 2 :(得分:-1)
我所做的与你想要达到的目标基本相同,我只是走了不同的路线。
整个过程都包含在NSOperation中,因此您可以控制调度内存使用情况。
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef);
NSUInteger bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
UInt8 *rawData = calloc((height * width * bitsPerComponent), sizeof(UInt8));
NSUInteger bytesPerRow = CGImageGetBytesPerRow(imageRef);
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
if (context)
{
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
// This is the place you get access to data trough rawData. Do whatever you want with it, when done, get image with
CGImageRef newImg = CGBitmapContextCreateImage(context);
}
OR
子类CALayer,覆盖drawInContext并使用CGBitmapContextGetData获取原始数据。对此没有太多经验,抱歉,但如果你想看到即时的变化 在基于用户输入的图像上,我这样做:
子类UIView和CALayer,它成为视图层并显示图像。视图获取输入,并且基于输入操纵图层类中的图像数据(来自CGBitmapContextGetData)。 甚至CATiledLayer也可以用这种方式用于巨大的图像。完成图像后,只需释放UIView并将其替换为新的。如果你需要,我很乐意提供帮助,只需点击这里。