Saturday, August 28, 2010

The autorelease lightbulb

In my use of some CoreData objects I ran into a situation where I was getting an EXC_BAD_ACCESS crash. This error essentially means that you are accessing an object that has already been released. I tried a couple of different ways to find the error and finally pinned the code down to this:

Photo *photo = [NSEntityDescription insertNewObjectForEntityForName:@"Photo" inManagedObjectContext:[myFF managedObjectContext]];

photo.name = [key objectForKey:@"name"];

photo.path = [key objectForKey:@"path"];

photo.photoOwner = person;

[[myFF managedObjectContext] save:&error];


[photo release];


The problem lies in the reference counting on the photo object. It turns out that insertNewObjectForEntityForName will return an autoreleased object per the documentation.

Return Value

A new, autoreleased, fully configured instance of the class for the entity named entityName.


Because I am releasing the photo object also it causes the aforementioned error.

Lesson learned: read the documentation!


Sunday, August 15, 2010

Useful XCode editor tip

It's always useful to have editor tips and tricks available. Here is a link to many for the XCode editor.

Sunday, August 8, 2010

Working with Core Data

You may have already noticed that transitioning from using your own Person and Photo classes to using the suggested NSManagedObject versions is not completely intuitive. In the first part of the Paparazzi assignment, I created my own Person and Photo classes to make managing the data a little easier; only to find out in part #2 that they would have you create Person and Photo objects that inherit from NSManagedObject. It sounds straight forward enough, right? Not so fast there Code Ninja. It is a little more complicated if you actually intend to use core data and have your new classes map to entities in a local database.

After struggling for a bit and enlisting the help of my peers, I was able to successfully port my Paparazzi part #1 over to a core data project and map new classes to my newly created database entities. In the next few paragraphs, I will explain the basics of how I accomplished this in an effort to ease the pain for anyone who has yet undertake this portion of the assignment.


NOTE: I do not recommend trying to adapt your existing project. Primarily because there are several hooks, default files and provided implementation by creating a core data project to start with. Otherwise, you will spend quite a bit of time trying to get your current project retrofitted. It will be far easier to create a new core data project and just copy over any existing code, xibs and AppDelegate logic you already have into to your new project.

Let's get started!
First, Create a new iPhone OS Windows-based Application. Make sure the "Use Core Data for storage is checked." Once you choose the suggested options, a project name and save your new project, you will notice a file unique to core data projects. Within your project hierarchy, under the Resources folder, you will have a "[ProjectName].xcdatamodelId" item. Expanding that item will reveal an "[ProjectName].xcdatamodel" file that will be the basis for your new Person and Photo classes.

Next, make sure you have the "[ProjectName].xcdatamodel" file selected (ensure it is not the parent file with a similar name). The should display a data model file with Entities, Properties and eventually a diagram once you establish some entities. This is where we will create our Person and Photo entities. Xcode will then create classes and map them to these database entities (very similar to any OR mapper you may have used in the past.

Create a Person entity by choosing the [+] icon beneath the Entity view. Once you have done this, you will notice a dialog to the right will appear for you to name the entity and set a few other properties. From the Property view, choose the [+] icon and create properties for "name", and photo. "name" will be an attribute of type NSString and "photos" will be a one-to-may relationship that you will eventually point to the Photo entity.

Create a Photo entity following the same steps as above. Add an NSString attribute for "name" and "path". Add a one-to-one relationship called "user" and choose a destination of Person. Now go back to your Person entity and have the one-to-many relationship "photos" destination point to the Photo entity.

We are almost done!
Now that we have our entities, attributes and relationships, it is time to generate the classes that will inherit from NSManagedObject. With one of your entities selected in the diagram, go to the Xcode menu and choose "File > New File". In the dialog, you will notice an option that is usually not there. This item is "Managed Object Class." This item us under the Mac OS X section. With this item selected, choose "Next". From the next screen, accept the defaults as appropriate and choose "Next". This last screen is the most important. Make sure that all the entities you want classes generated for are selected. By default, validation methods are not generated - which is fine for the Paparazzi assignment and you can change it later. Choose "Finish".

The newly created classes will automatically import "CoreData" and will inherit from "NSManagedObject". If you look at each class you will see they are mostly normal classes. What is really different is how you instantiate (alloc, init) them. For the most part you will always do this through a class called "NSEntityDescription" using a method called "insertNewObjectForEntityForName" or other depending on if you are creating or accessing.

That's it!
From here you should probably make sure you are up to speed on the Paparazzi assignment. There are some classes like FlikrFetcher they want you to use as a singleton to create your objects to insert in the database. Covering that would involve some more discussion and I will save that for a later date. If you found this entry helpful and need more info on instantiating these items and adding them to the database, send me an email or add a comment and I will do my best to get back to you directly or add another entry.