2011-06-03 153 views
2

我正在使用CGDataProviderCreateWithData(最终)从mableced字节数组创建一个UIImage。我称CGDataProviderCreateWithData这样的:使用CGDataProviderCreateWithData回调

provider = CGDataProviderCreateWithData(NULL, dataPtr, dataLen, callbackFunc); 

其中

dataPtr是用于将图像数据字节的先前malloced阵列, DATALEN是dataPtr阵列中的字节数,并且如描述 callbackFunc在CGDataProviderCreateWithData文档:

void callbackFunc(void *info, const void *data, size_t size); 

的回调函数是数据提供者被释放时调用,所以我可以自由()dataPtr那里,但我可能要孔蒂nue使用它(dataPtr),并在稍后阶段释放它。这个代码块会被多次调用,并且流将类似于:

  1. 的malloc(dataPtr)
  2. 创建图像(调用CGDataProviderCreateWithData等)
  3. 显示图像
  4. 释放图像(和所以发布)由CGDataProviderCreateWithData创建的数据提供商)
  5. 继续使用dataPtr
  6. 免费(dataPtr

因此1..6可以被执行多次。我不希望dataPtr挂在程序的整个执行过程中(它可能会改变大小),所以我想根据需要malloc /释放它。

的问题是,我可以从CGDataProviderCreateWithData回调不自由(dataPtr),因为我仍然想使用它,所以我想稍后释放它的一些时间 - 我不能释放它,直到我知道,数据提供者不再需要它(据我所知,CGDataProviderCreateWithData使用我传递的数组,它不需要副本)。

我不能做以上(1),直到我知道它可以释放并重新malloc dataPtr,所以我真正想要做的是阻止等待数据提供者被释放(嗯,我想知道我是否应该重新输入1..6代码块,在数据提供者被释放之前我不能这样做)。这将是 - 我创建数据提供者,创建图像并立即显示并释放数据提供者。问题在于数据提供者在UIImage发布并且完成之前并未实际发布。

我对objective-c和iOS很合适。我错过了明显的东西吗?

回答

-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并将其替换为新的。如果您需要任何帮助,我会很乐意提供帮助,只需在此处ping。

+0

但是我不是已经拥有它了吗?我已拥有所有权 - 我不会让回调免费 - 我只想知道我什么时候可以免除罚款(即数据提供者完成后)。 – JeffR 2011-06-03 01:59:00

+0

啊,但是如果我创建一个副本,那么我的应用程序的内存使用量将相应增加 - 如果这是一个大图像,我在内存中有两个数据字节副本......我不能等到数据提供程序完成它? – JeffR 2011-06-03 02:02:40

+0

您也拥有CGDataProvider的所有权,因为您使用CGDataProviderCreateWithData创建了它,并且您负责通过CGDataProviderRelease处理它。我在回答中告诉过你如何创建一个可以与创建图像,显示器,免费数据提供程序等分开使用的图像数据副本。请问我为什么要以这种方式进行1-6步?是否存在图像处理? – TheBlack 2011-06-03 02:06:04

0

我遇到了类似的问题。我想使用CGImageCreateWithJPEGDataProvider,所以使用CGDataProviderRef和malloc'd字节数组。在创建数据提供者引用后的某个时候尝试释放字节数组时,我遇到了同样的问题。 这是因为数据提供者引用接管了字节数组的所有权,所以只能在引用完成后才能被引用释放。 我同意@TheBlack,如果你需要其他地方的数据,请复制一份。

0

如果你为malloc的内存提供商的数据,你真的想要free它在回调。不要试图以任何方式规避这种情况。它很容易泄漏,并容易受到简单的内存问题。

话虽如此,有两个简单的解决方案,解决您的问题。要么:

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

  • 而不是使用的CGDataProvider方法void *引渡的,使用CFData再现(如CGDataProviderCreateWithCFData),然后就可以维护自己的强引用这个数据对象(或者,如果在非ARC的代码,做自己数据对象的retain)。直到解析所有强引用为止(或者在非ARC代码中,您的所有手动retain调用都使用相应的releaseautorelease调用进行解析)之后,该对象才会被释放。

无论使用哪种方法,你可以继续让CGProviderRef管理内存,因为它认为合适的,但你可以继续使用数据对象为自己的目的了。