Tag Archives: objective-c

Capture Save/Load/Remove Image in documents directory

NSFileManager offers a convenient way to write images to and load them from the documents directory.
If you’re frequently doing that in your project, I suggest to wrap up NSFileManager support in three simple methods:

Save/Load/Remove Image Methods

//saving an image

- (void)saveImage:(UIImage*)image:(NSString*)imageName {

NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format.

NSFileManager *fileManager = [NSFileManager defaultManager];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]];

[fileManager createFileAtPath:fullPath contents:imageData attributes:nil];

NSLog(@"image saved");

}

//removing an image

- (void)removeImage:(NSString*)fileName {

NSFileManager *fileManager = [NSFileManager defaultManager];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", fileName]];

[fileManager removeItemAtPath: fullPath error:NULL];

NSLog(@"image removed");

}

//loading an image

- (UIImage*)loadImage:(NSString*)imageName {

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]];

return [UIImage imageWithContentsOfFile:fullPath];

}

Now, you can easily save an image like:

[self saveImage: myUIImage: @"myUIImageName"];

or load it like:

myUIImage = [self loadImage: @"myUIImageName"];

or remove it like:

[self removeImage: @"myUIImageName"];

Capture an image

– (UIImage*) getGLScreenshot {
NSInteger myDataLength = 320 * 480 * 4;

// allocate array and read pixels into it.
GLubyte *buffer = (GLubyte *) malloc(myDataLength);
glReadPixels(0, 0, 320, 480, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

// gl renders “upside down” so swap top to bottom into new array.
// there’s gotta be a better way, but this works.
GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
for(int y = 0; y <480; y++) { for(int x = 0; x <320 * 4; x++) { buffer2[(479 - y) * 320 * 4 + x] = buffer[y * 4 * 320 + x]; } } // make data provider with data. CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL); // prep the ingredients int bitsPerComponent = 8; int bitsPerPixel = 32; int bytesPerRow = 4 * 320; CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; // make the cgimage CGImageRef imageRef = CGImageCreate(320, 480, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); // then make the uiimage from that UIImage *myImage = [UIImage imageWithCGImage:imageRef]; return myImage; } - (void)saveGLScreenshotToPhotosAlbum { UIImageWriteToSavedPhotosAlbum([self getGLScreenshot], nil, nil, nil); } [/sourcecode]

NIBs or code? Why not both? Here’s nib2objc.


(Somehow this project seems to me so simple, that I’m sure someone has done this before. Anyway). This is my feeble attempt to bring an answer to the eternal dichotomy between those arguing about the relative benefits of creating user interfaces via Interface Builder or via pure Objective-C code: let me introduce nib2objc.
Continue reading NIBs or code? Why not both? Here’s nib2objc.

Trace freed/deallocated instances of objects

This procedure has saved me more than once, so I need to document it throughly for everyone! There are cases where I see messages (in the debugger console) that are like this;

 >-[NSFetchedResultsController class]: message sent to deallocated instance 0x11957d0

Sometimes, it will talk about “freed” instead of deallocated. That address at the end is important. To track down the line of code where the object was allocated, you’ll need to set a couple environment settings. To do this, right click on the executable you’re trying to debug and select “get info”. Select the “arguments” tag and set the values shown below;

MallocStackLoggingNoCompact 1

NSZombieEnabled YES

debug environment settings

(be sure to disable these when you’re done. They should not be enabled for a production build!)

Next, run your program and test enough to generate the error. In the Debugger Console, copy that hex address value, then type the command;

(gdb) info malloc-history <paste-address-here>

You should see something like this;
Stack – pthread: 0xa0416720 number of frames: 28
0: 0x9264382d in malloc_zone_calloc
1: 0×92643782 in calloc
2: 0×93611618 in _internal_class_createInstanceFromZone
3: 0x9361ab08 in _internal_class_createInstance
4: 0x3020275c in +[NSObject allocWithZone:]
5: 0x3020264a in +[NSObject alloc]
6: 0x3d92 in -[AMRAPViewController fetchedResultsController] at /Users/dkavanagh/CrossFit Timer/Classes/AMRAPViewController.m:146
7: 0x3a18 in -[AMRAPViewController viewWillAppear:] at /Users/dkavanagh/CrossFit Timer/Classes/AMRAPViewController.m:96
8: 0x3097c945 in -[UINavigationController _startTransition:fromViewController:toViewController:]
9: 0x30977c33 in -[UINavigationController _startDeferredTransitionIfNeeded]
10: 0x3097d01e in -[UINavigationController pushViewController:transition:forceImmediate:]

The first line below the object alloc (in my case, line 6) will show where the offending object was allocated and should really help in tracking down the free/dealloc problem.