Sorry this isn’t in tutorial format, but I want to capture this so I don’t have to search quite so long next time ;-)!
While I’ve done several iOS apps, I’m getting started on my first Mac app. If you’ve spent a year or so with iOS and you think that jumping to the Mac’s AppKit will be a breeze, brace yourself! Yes, they both use Objective-C. Yes, they both have a lot in common. But there are some major differences between UIKit and AppKit. And then there’s Cocoa Bindings that really make Mac programming fun, but there is definitely a learning curve.
So, on with this post…I’m using Core Data with Bindings to my interface. On one view, I’m binding to an NSImageView, using the imageWell capability which lets you drag images right onto the image view and magically have them populate an NSManagedObject’s Binary Data attribute. You hook up your NSImageView to the Value binding of your selection and give it a value transformer of “NSUnarchiveFromData”, and it magically transforms binary data back to an image.
It’s all smooth as butter, but now I’m ready to import some contacts using the ABPeoplePickerView. This also works really well once you get all the right frameworks added and classes imported.
You can easily loop through the selectetRecords property of your people picker view to get ABPerson records that have all of the goodies from the Mac Addressbook. You can also easily get the person’s image from the addressbook just by accessing the imageData property like: person.imageData
That gives you a pure NSData object. Now you want to store that in your Core Data store. You might think you could just do this:
// DOES NOT WORK when you're applying the NSUnarchiveFromData value transformer in your NSImageView value binding Contact *contact = [NSEntityDescription insertNewObjectForEntityForName:@"Contact" inManagedObjectContext:context]; // we have defined a binary data attribute named image in our model ABPerson *person = [peoplePickerView.selectedRecords lastObject]; contact.image = person.imageData;
When you try to display your Core Data object in your bound interface, that NSImageView will just stare dumbly back at you.
Here’s how you need to store that image to get it to work. The trick is converting to an NSImage and using the NSArchiver class to archive it for storage:
// This WORKS when you're applying the NSUnarchiveFromData value transformer in your NSImageView value binding Contact *contact = [NSEntityDescription insertNewObjectForEntityForName:@"Contact" inManagedObjectContext:context]; ABPerson *person = [peoplePickerView.selectedRecords lastObject]; NSImage *tempImage = [[NSImage alloc] initWithData:person.imageData]; contact.image = [NSArchiver archivedDataWithRootObject:tempImage];
Hope that helps!!