使用CGDataProviderCreateWithData回调

时间:2011-06-03 01:36:57

标签: iphone objective-c

我正在使用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. 的malloc(dataPtr)
  2. 创建图像(调用CGDataProviderCreateWithData等)
  3. 显示图片
  4. 发布图片(以及由CGDataProviderCreateWithData创建的发布数据提供程序)
  5. 继续使用dataPtr
  6. 自由(dataPtr)
  7. 所以1..6可以多次执行。我不希望dataPtr在程序的整个执行过程中徘徊(并且它的大小可能会发生变化),所以我想在必要时使用malloc / free。

    问题是我无法在CGDataProviderCreateWithData的回调中释放(dataPtr),因为我仍然想要使用它,所以我想在一段时间之后释放它 - 我不能释放它直到我知道它数据提供者不再需要它(据我所知,CGDataProviderCreateWithData使用我传递的数组,它不需要复制)。

    我不能做上面的(1)直到我知道可以释放和重新malloc dataPtr,所以我真正想做的是阻止等待数据提供者被释放(好吧,我想知道我是否应该重新输入1..6代码块,在数据提供程序被释放之前我无法做到这一点。它将是 - 我创建数据提供者,创建图像并立即显示它并释放数据提供者。问题是数据提供程序在UIImage发布并完成后才会实际发布。

    我是Objective-c和iOS的新手。我错过了一些明显的东西吗?

3 个答案:

答案 0 :(得分:1)

如果你malloc提供者数据的内存,你真的想在回调中free。不要试图以任何方式试图规避这一点。它太容易泄漏,容易受到简单的内存问题的影响。

话虽如此,有两个简单的解决方案可以解决您的问题。之一:

  • 制作您自己要与提供商分开管理的数据的副本;或

  • 使用void *再现(例如CGDataProvider),而不是使用CFData方法的CGDataProviderCreateWithCFData再现,然后您可以保留自己的强引用对于此数据对象(或者如果在非ARC代码中,请执行您自己的retain数据对象)。在解决所有强引用之前,不会取消分配对象(或者,在非ARC代码中,所有手动retain调用都通过相应的releaseautorelease调用解析。

使用这两种方法之一,您可以继续让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并将其替换为新的。如果你需要,我很乐意提供帮助,只需点击这里。