views:

417

answers:

3

I am having a baffling issue while trying to fill an NSMutableArray with UIImages.

CGBitmapInfo bitmapInfo = kCGBitmapByteOrderMask;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

while(...)     // <--- Iterates through data sets
{

          CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, numBytes, NULL);
          CGImageRef cImage = CGImageCreate(iw, ih, 8, 32, 4 * iw, colorSpace, bitmapInfo, provider, NULL, NO, renderingIntent);
          UIImage *finalImage = [UIImage imageWithCGImage:cImage];


          [images addObject:finalImage]; // <--- Declared and instantiated earlier

          [delegate sendImage:finalImage];

          CGImageRelease(cImage);
          CGDataProviderRelease(provider);
}

CGColorSpaceRelease(colorSpace);

[delegate operationCompletedWithImages:images];

That is how I have the code running. So I basically have a function running in the while statement that returns the next set of bitmap data, I then create a UIImage and store it into the mutable array.

I've tested this by writing each file to disk and then accessing them which results in the proper set of images. The problem is when using the array to keep data in memory, accessing any image object in the array I get the same exact image over and over. The image is also always the last image of the set.

I've tried testing the contents by setting the array as a UIImageView animation array and by using an NSTimer to cycle the contents. Either way it is just the same image (last image pulled) over and over.

I have this operation running inside a subclassed NSOperation object so it doesn't block the interface. Another interesting aspect here is that when the images array sent with operationCompletedWithImages was giving me the array of duplicate images I tried using the sendImage message and store the images in a different array inside the delegate object (thinking maybe it was a threading issue). This gave me the same results.

I've been stuck on this for over a week with no progress. I've never seen anything like it and I can't find anyone else who has had a similar issue.I would be happy to provide extra information if someone feels it would assist in solving this issue.

If anyone could provide any assistance I would greatly appreciate it.

A: 

Not sure if this is the problem, but you should probably be notifying your delegate of the changes on the main thread, not the thread that the NSOperation is running on.

[delegate performSelectorOnMainThread:@selector(sendImage:) withObject:finalImage waitUntilDone:YES];

And likewise for the last message. If the delegate is modifying anything UIKit-related, it must be invoked on the main thread!

PfhorSlayer
Thank you! that is definitely a step in the right direction. When I perform the sendImage selector on the main thread I'm definitely getting the proper images.Now I am adding those images to an array in the delegate object (main thread). The problem is that once they are all added and I try to review them they are all the same.Very strange. So I'm receiving the proper images from the background thread but somehow the array is just storing copies of the last image received...
Matthew McGoogan
What do you mean by 'all the same'? Do all the images have the same content, or are the the *exact same instance*? Check the pointer values being stored in your array!
PfhorSlayer
Matthew McGoogan
A: 

One might assume that the NSMutableArray would handle the memory management of the object being added to it, but perhaps because you're dealing with the C level Quartz helpers/ Core wrappers this may not be the case.

In other image manipulating methods I've experimented with they are usually wrapped in an autorelease pool if they are involved with threads.

Have you tried experimenting with release/autorelease on the finalImage?

David Sowsy
I've played around with modifying the retain counts to no avail. I figured it was a shot in the dark anyway as I couldn't understand why it would cause the duplicate objects in the array.What is really making my head spin with this - in the delegate object (on the main thread) I tried pulling a CGImageRef from each UIImage as they were sent via sendImage and allocing a new UIImage with the CGImageRef to get a new copy before adding to the array. I STILL get an array of the same image over and over (still the last image added).
Matthew McGoogan
A: 

Figured out the problem. Turned out to be an issue with the backing data pointer.

Where before I was accessing data everytime thinking it would iterate and overwrite with new contents, and the new contents would be plugged into my CGDataProviderRef. This was not the case, I basically ended up supplying a pointer to the same backing data for the Provider. The solution was to copy the data into an NSData object and use that copy for the DataProvider.

So instead of:

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, numBytes, NULL);

It would be:

NSData *pxData = [[NSData alloc] initWithBytes:pFrameRGB->data length:numBytes];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)pxData);
Matthew McGoogan