views:

84

answers:

2

Im writing a project in Objective-C but I'm relying quite much on plain old C since there's OpenGL involved.

I have a data blob that I read to memory from a file in the following way:

NSString *path = [[NSBundle mainBundle] pathForResource:@"iPadTest" ofType:@""];
NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
data = [file readDataToEndOfFile];
currentImage = [ReadDataFiles getOrganizedImageData:data];

The last function gives me a structure where the data is a little more accessible but there is still three lengthy data blobs of image data. It begins like this:

ImageData *organizedImageData = malloc(sizeof(ImageData));

// IMAGE DIMENSIONS
UInt64 *rawData = (UInt64 *) data.bytes;
organizedImageData->imageDimensions.x = *rawData;
rawData++;
organizedImageData->imageDimensions.y = *rawData;
rawData++;
organizedImageData->imageDimensions.z = *rawData;

// IMAGE 1
rawData++;
organizedImageData->image1Data = (UInt8*)rawData;
// IMAGE 2
rawData++;
organizedImageData->image2Data = (UInt8*)rawData;

// etc...

The problem is that when the data reaches the OpenGL functions something else has written in the same memory. The result is different every time but the data is never persistent.

When I tell the debugger to pause when those adresses are beeing changed I end up in assembly code that I don't can make anything ou of.

How and where should i allocate the memory space so that the rest of the program doesn't fool with it?

+2  A: 

The problem is that you do not own the variable called data and it's almost certainly being deallocated the first time you hit an autorelease pool drain (or if you are using GC, it is disappearing after it goes out of scope). When data goes away, all those pointers you are carefully creating to point into [data bytes] are left dangling.

In the reference counted environment, you need to send -retain to data before the autorelease pool is drained (which is guranteed to happen when you return to the run loop) and then you need to release it when you are done with the data in it. In the GC environment, you just need to keep a strong reference e.g. make it an ivar of some object.

Alternatively, you can copy the data somewhere else instead of just creating pointers to bits of it.

JeremyP
A: 

Sorry, I can't post comments yet, so here's a complete answer:
Like jeremy said, you don't own the reference to data, so it will go away!

There are—however—a few ways of ensuring it's viability:

  1. Store data (and I really mean the pointer here!) within your struct so you can release it when you're done using it.
    If you're running under GC, define that field as __strong void * or (since NSData is toll-free-bridged to CFData) call CFRetain( (CFDataRef) data ) which is actually not a noop in GC-ed code! (This has you covered in GC-ed and ref-counted environments BTW...)
  2. Create that object through [[NSData alloc] initWithContentsOfFile:] and stash it into your struct. (GC-notes apply here as well!)
  3. malloc the memory for your image and use -[NSData getBytes:range:] with that.
    This will probably mean a noticable performance hit, though.

Whichever way you choose, don't forget to clean up after yourself—CFRelease() will probably be the nicest solution in case 1 and 2 because it covers GC and ref-counting.


BTW (And I hope this doesn't come off as rudeness!):
Is there a certain reason that...

  1. you are using NSFileHandle instead of going straight through NSData-methods?
  2. you have your data as a blob that way?
    You could store it as a binary-plist through NSKeyedArchiver and retrieve it a little more elegant than through pointer gymnastics and yet with little overhead.

Oh and the big one:
What exactly are you doing/trying to do here:

// IMAGE 1
organizedImageData->image1Data = (UInt8 *)rawData;
rawData++;
// IMAGE 2
organizedImageData->image2Data = (UInt8 *)rawData;
rawData++;

I cannot make much sense of that.
Suggestion 2 would probably simplify this as well, by the way :-)

danyowdee