-[NSBitmapImageRep bitmapData] is useless and possibly dangerous
I wanted to do the most basic of all graphics programs. Draw
stuff in a bitmap repeatedly and display it. This used to go like
this, when I started coding:
10 SCREEN = PEEK (88) + PEEK (89) * 256 20 POKE SCREEN + y * 40 + x, 55
and presto something happened on the screen.
What I thought the way to do this in AppKit was to use a NSBitmapImageRep and use it wrapped in a NSImage to be displayed in a NSImageView:
- (void) applicationDidFinishLaunching:(NSNotification *)aNotification { NSImage *image; unsigned char *buf; buf = malloc( 512 * 512 * 3); NSLog( @"0) %s bitmap@ %p", __PRETTY_FUNCTION__, buf); _bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&buf pixelsWide:512 pixelsHigh:512 bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bitmapFormat:0 bytesPerRow:0 bitsPerPixel:0]; NSLog( @"1) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]); image = [[[NSImage alloc] initWithSize:NSMakeSize( 512, 512)] autorelease]; NSLog( @"2) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]); [image addRepresentation:_bitmap]; NSLog( @"3) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]); [image setCacheMode:NSImageCacheNever]; NSLog( @"4) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]); [imageView setImage:image]; NSLog( @"5) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]); [imageView display]; NSLog( @"6) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]); }
My expectation being, that I could then change the NSBitmapImageRep and then just call -display in my NSImageView to refresh the screen.
This expectation was wrong. I can't do that.
2013-09-08 15:59:50.183 RandomBitmap[2181:303] 0)
-[MulleAppDelegate applicationDidFinishLaunching:] bitmap@
0x107300000
2013-09-08 15:59:50.183 RandomBitmap[2181:303] 1)
-[MulleAppDelegate applicationDidFinishLaunching:] bitmap@
0x107300000
2013-09-08 15:59:50.183 RandomBitmap[2181:303] 2)
-[MulleAppDelegate applicationDidFinishLaunching:] bitmap@
0x107300000
2013-09-08 15:59:50.183 RandomBitmap[2181:303] 3)
-[MulleAppDelegate applicationDidFinishLaunching:] bitmap@
0x107300000
2013-09-08 15:59:50.184 RandomBitmap[2181:303] 4)
-[MulleAppDelegate applicationDidFinishLaunching:] bitmap@
0x107300000
2013-09-08 15:59:50.184 RandomBitmap[2181:303] 5)
-[MulleAppDelegate applicationDidFinishLaunching:] bitmap@
0x107300000
2013-09-08 15:59:50.189 RandomBitmap[2181:303] 6)
-[MulleAppDelegate applicationDidFinishLaunching:] bitmap@
0x107475100
As a code lawyer would say, as soon as I give NSBitmapImageRep my buffer it apparently becomes NSBitmapImageRep's private buffer. And that although I am responsible for freeing it and (ironically) must not free it as long as NSBitmapImageRep is alive. But NSBitmapImageRep apparently may choose to swap out the bitmap with one of its own - and will! Since there is neither some documentation about this nor a notification, when it does that, the value returned by bitmapData is useless, because you can't know, how long the buffer is actually valid. It's undefined and potentially even dangerous.