Code, Code, Revolution!
UPDATED 2010-04-03
iPhone OS 3.0 is out this week and while the new iPhone 3GS was pretty disappointing hardware wise, the new iPhone OS is really packed with new cool frameworks and APIs. I’m working on a lot of projects back and fourth depending on what I feel like working with at the moment. After we released the first app, Hitta Hem, I wrote a bunch of articles based on that work and got kind of tired of iPhone development. I’ve started working again on some new things around iPhone OS 3.0 features and I thought I’d share some Core Data stuff.
Core Data is new in iPhone OS 3.0, but has been around for OS X application developers for quite some time. Since I’m NOT an OS X application developer this framework was totally new to me and it’s a great addition to the iPhone SDK. So what exactly is the Core Data framework? If you are familiar with the entity framework in .NET, it’s something similar. Core Data is an abstraction layer on top of a sqlite database which enables developers to more easily implement data-centric applications. Personally I never got around to do much with sqlite but I touched it enough to appreciate what Core Data brings to the table. My main issues with sqlite are poor tooling support and a limited range of documentation and samples. I’m used to working with Microsoft products and even though I’m aware that MS has the best tooling support in the world, the tooling provided for sqlite sucks!
What the Core Data framework provide is an easy way to model your data storage around entities (classes) with relationships between them. If you’re not familiar with relational databases such as SQL, Core Data is for you! Core Data is a model first framework that generate the database and tables automatically from your model, it can also generate classes for your model entities. However, if you have worked with the entity framework in .NET, you’ll get a bit disappointed over the limited functionality. But we have to remember, the iPhone is just a phone.
This application is simple and not for much use as it is, but it’s a useful example for a real application.
I’ve placed the source data in an XML file which is in the application bundle, the XML is parsed and stored in the object model. The data is made up of Swedish counties, provinces and cities where each county has multiple provinces and the provinces has multiple cities. In SQL-terms they have a one-to-many relationship. You can see the model on the picture below.
If you read up on Apples’ documentation they encourage everyone to add inverse relationships for all relationships in order to keep the data consistent. In my model I’ve added a one-to-many relationship from County to Province (named CountyToProvince) with action set to cascade. That means if a County is removed so are all provinces related to it. The inverse relationship is called “ProvinceToCounty” on the Province object. The inverse relationship enables you to access the County object of a Province object.
The province entity also has a one-to-many relationship but with City, called “ProvinceToCcounty”. City also has an inverse relationship to Province called “CityToProvince”.
The reason for cascading events is that we can easily clean up our entire model by just removing the top level (County).
If you’re interested in how things actually work (like me) you can find and peek into the sqlite database created from your model. The iPhone simulator stores application files in /Users/<your user name>/Library/Application Support/iPhone Simulator/User/Applications/<random guid>/ and you will find a file named Location.sqlite inside the “Documents”-folder.
To the left is an image of what the database actually looks like inside (using SQLite Manager, the Firefox plug in(!?)). As you can see the Core Data framework created two additional tables other than what we actually modeled in the designer and for some reason the Apple engineers love the letter Z. With SQLite Manager you can also take a look inside the tables to see the values. The relationships work like you would expect them to, the tables reference each other by the primary key which is just an integer that gets incremented.
I decided to feed the application using XML because it’s both simple and makes sense for a real world application. You could easily request the XML from a web service and store it in your app and not have to read live from the web all the time. Of course, if your data is massive, this could be a problem but you could also split the data requests into smaller chunks and just store what your fetch for re-use and perhaps an offline mode.
Here’s what my XML structure looks like
<loc> <county name="Norrbotten"> <province name="Arjeplog"> <city name="Arjeplog"/> </province> </county> </loc>
I’ve created a parser for my XML. When it reads a county-element it asks the object model context for a new County object. If there are province-elements they are created and added to the County objects’ CountyToProvince relation collection. If there are city-elements they are created and added to the County object. When there are no more cities and provinces the end-element event fires for the county-element and that’s when I store all changes which means they are persisted down into the sqlite database by Core Data.
Creating a object from the Core Data context is easy as pie:
currentCounty = (County *)[NSEntityDescription insertNewObjectForEntityForName:@"County" inManagedObjectContext:managedObjectContext];
Adding a Province child object to a County is done using the method addCountyToProvinceObject which has been generated for us automatically:
[currentCounty addCountyToProvinceObject:currentProvince];
Fetching data from the object model is very easy, no SQL skills required, almost. To simplify fetching data and reducing the amount of code I created a simple helper class with static methods that do most of the work.
+(NSMutableArray *) searchObjectsInContext: (NSString*) entityName : (NSPredicate *) predicate : (NSString*) sortKey : (BOOL) sortAscending : (NSManagedObjectContext *) managedObjectContext { NSFetchRequest *request = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext]; [request setEntity:entity]; // If a predicate was passed, pass it to the query if(predicate != nil) { [request setPredicate:predicate]; } // If a sort key was passed, use it for sorting. if(sortKey != nil) { NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; [request setSortDescriptors:sortDescriptors]; [sortDescriptors release]; [sortDescriptor release]; } NSError *error; NSMutableArray *mutableFetchResults = [[[managedObjectContext executeFetchRequest:request error:&error] mutableCopy] autorelease]; [request release]; return mutableFetchResults; } +(NSMutableArray *) getObjectsFromContext: (NSString*) entityName : (NSString*) sortKey : (BOOL) sortAscending : (NSManagedObjectContext *) managedObjectContext { return [self searchObjectsInContext:entityName :nil :sortKey :sortAscending :managedObjectContext]; }
You can either retrieve all objects of a given type buy calling getObjectsFromContext. All you have to do is pass the entity name of your object and the rest is optional except the managedObjectContext. It’s very useful to let Core Data sort your data by passing the sortKey, which is the name of the column, or property if you like, to sort by. Sorting can be done ascending or descending to you liking.
If you only want to retrieve specific parts of you data you must use the NSPredicate object to define which object you want. A predicate for getting all child objects of a given parent object can be done like so:
predicate = [NSPredicate predicateWithFormat:@"(ProvinceToCounty == %@)", selectedObject];
where selectedObject is the parent object of the children you want to fetch. Just pass the predicate and the entity name of the objects you want to searchObjectsInContext and you get them back as a mutable array. The helper class is just to reduce the amount of duplicated code needed to fetch objects.
In my application the UITableView will load either all entities of a given entity name or filter them down by a predicate. This way the same UITableView class is used for all views in the application. When a row is selected a predicate is created to get the child objects of the selected entity and then passed to a new instance of RootViewController:
// Override to support row selection in the table view. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if(self.entityName == @"County" || self.entityName == @"Province") { // Create a new table view of this very same class. RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain]; // Pass the managed object context rootViewController.managedObjectContext = self.managedObjectContext; NSPredicate *predicate = nil; NSManagedObject *selectedObject = [entityArray objectAtIndex:indexPath.row]; if(self.entityName == @"County") { rootViewController.entityName = @"Province"; // Create a query predicate to find all child objects of the selected object. predicate = [NSPredicate predicateWithFormat:@"(ProvinceToCounty == %@)", selectedObject]; } else if(self.entityName == @"Province") { rootViewController.entityName = @"City"; // Create a query predicate to find all child objects of the selected object. predicate = [NSPredicate predicateWithFormat:@"(CityToProvince == %@)", selectedObject]; } [rootViewController setEntitySearchPredicate:predicate]; //Push the new table view on the stack [self.navigationController pushViewController:rootViewController animated:YES]; [rootViewController release]; } }
There you have it. Core Data is an awesome addition to the iPhone SDK and if you use it wisely you can improve your application by saving lots of expensive server round-trips to fetch data and perhaps also store data for offline usage.
Remember, if you make changes to an existing data model your app will crash with an exception: NSInternalInconsistencyException. This is because the database which was previously created doesn’t match your new model. You can code your app to remove the database file and then create a new. My updated example contains the code.
* UPDATED 2010-04-03: Fixed warnings reported by XCode analyzer. Added a call button and an in-app-email button to the details page.
With this blog I try to provide useful tips and solutions for programming .NET, Objective-C and more. My name is Björn Sållarp, and I love writing code.
prairie dogg
June 29th, 2009 at 9:02 am
Thanks for this post, I’m trying to get a grip on CoreData for the iPhone and this definitely helped.
Julien
June 30th, 2009 at 8:41 am
Brilliant ! Also, the xml import is a very good addition that will help me a lot !
Thanks a lot !
kdatesha
July 1st, 2009 at 5:23 am
Great overview on real world core data use for iPhone. Unfortunately the sample project crashes like clock work because of memory leak somewhere.
Björn Sållarp
July 1st, 2009 at 9:24 am
kdatesha, when does it crash? I’ve tested this sample exensively and checked it with “Leaks” without finding anything. Are you sure you have iPhone SDK 3.0 final installed and that you are running the sample in the 3.0 simulator?
// Björn
Joshua
July 7th, 2009 at 7:51 pm
This is a great tutorial, thanks for the help!
I have a question, however. In playing with the code, I am trying to push to a new view when I select the province, but I can’t figure out how to do this. So far, everything I have tried (and I have tried a lot of things that work for me in other apps) has crashed the app whenever I select a province. Any tips? Thanks again.
Björn Sållarp
July 7th, 2009 at 8:23 pm
Hi Joshua,
Just to make sure I understand what you are doing. You don’t want to open the city view, instead you want to open a view with an image for instance?
If so, you must change the code in RootViewController, method: – (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Change the if statement from:
if(self.entityName == @”County” || self.entityName == @”Province”)
to:
if(self.entityName == @”County”)
then add an else method after that. Here’s an example:
if(self.entityName == @”County”)
{
// Create a new table view of this very same class.
RootViewController *rootViewController = [[RootViewController alloc]
initWithStyle:UITableViewStylePlain];
// Pass the managed object context
rootViewController.managedObjectContext = self.managedObjectContext;
NSPredicate *predicate = nil;
NSManagedObject *selectedObject = [entityArray objectAtIndex:indexPath.row];
if(self.entityName == @”County”)
{
rootViewController.entityName = @”Province”;
// Create a query predicate to find all child objects of the selected object.
predicate = [NSPredicate predicateWithFormat:@"(ProvinceToCounty == %@)", selectedObject];
}
[rootViewController setEntitySearchPredicate:predicate];
//Push the new table view on the stack
[self.navigationController pushViewController:rootViewController animated:YES];
[rootViewController release];
}
else if(self.entityName == @”Province”)
{
TestView* view = [[TestView alloc] initWithNibName:@”TestView” bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:view animated:YES];
[view release];
}
In this case, TestView is my new normal UIViewController class displaying a label.
Hope this is the answer to your question. If not, ask again
.
Cheers!
Joshua
July 8th, 2009 at 8:39 pm
Thanks for the fast and very thorough response.
This is pretty much what I had been doing, so seeing it done right does give me some confidence… but the big problem is this still doesn’t work and I have no idea why!
I am trying to push to a new view (created with New > User Interface > View XIB) and it is declared as a UIViewController in its header file, like this:
@interface MainView : UIViewController {…
I can push to this same exact view using a drill down plist, so I’m stumped. I’m very new to programming, so any more help would be greatly appreciated.
Thanks again for all the help you’ve been!
Joshua
July 9th, 2009 at 8:52 pm
I just want to follow up to my last post.
I have no idea what was wrong – but I deleted “Controller” from UIViewController (leaving just UIView) in my last post and tried to run the app. Of course, I got some errors and couldn’t progress. So I pasted (not even re-typed) “Controller” back to UIViewController and since then everything has worked perfectly as it should. Very, very strange and frustrating. Must be a bug in the SDK, I guess.
Thanks again for the great tutorial.
Björn Sållarp
July 11th, 2009 at 12:04 pm
Hi Joshua,
I’m glad it worked out for you! Sometimes weird things like that just happen.
Good luck with your app!
Joshua Lund
July 14th, 2009 at 5:41 pm
Björn,
You have been so helpful, but now I have one more question.
Now that this new view is working, do you know how I would display the City name in a text label in the new view? I am struggling with Core Data (okay, Objective-C as a whole) and can’t seem to work this out on my own (it seems like it would be a pretty simple thing). Thanks again.
P.S. I included my last name with the hope that it would earn me some extra points for your help! :-p
Björn Sållarp
July 14th, 2009 at 5:56 pm
You can do it in two ways but this is the simplest way:
First you need to create a property on your new view class, call it CityName of type NSString*, don’t forget to synthesize it.
When you have created your view in the UITable view, in my example:
TestView* view = [[TestView alloc] initWithNibName:@”TestView” bundle:[NSBundle mainBundle]];
before you push it to the view controller, set the property you created. Example with TestView
TestView.CityName = selectedObject.Name;
selectedObject is the CoreData entity that the user selected in the UITableView and it carries the property Name.
Now you can set the label text to that property in your TestView class, at ViewDidLoad for example.
Another way of doing it would be to create a custom constructor for your view and pass the variable as a parameter to that constructor when creating the class.
Hope that helps.
Joshua Lund
July 14th, 2009 at 7:52 pm
I feel like I am really close to understanding this, but I’m not there yet. This is how the relevant section of my RootViewController code looks (with some notes):
if(self.entityName == @”County”) { // Create a new table view of this very same class. RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
// Pass the managed object context rootViewController.managedObjectContext = self.managedObjectContext; NSPredicate *predicate = nil; NSManagedObject *selectedObject = [entityArray objectAtIndex:indexPath.row];
if(self.entityName == @”County”) { rootViewController.entityName = @”Province”;
// Create a query predicate to find all child objects of the selected object. predicate = [NSPredicate predicateWithFormat:@"(ProvinceToCounty == %@)", selectedObject];
}
[rootViewController setEntitySearchPredicate:predicate];
//Push the new table view on the stack [self.navigationController pushViewController:rootViewController animated:YES]; [rootViewController release]; } else if(self.entityName == @”Province”) { TestView* view = [[TestView alloc] initWithNibName:@”TestView” bundle:[NSBundle mainBundle]];
// without the code below, I would get an error: ’selectedObject’ undeclared
NSManagedObject *selectedObject = [entityArray objectAtIndex:indexPath.row];
//with the above code in place I now get the error: request for member ‘Name’ in something not a structure or union
TestView.CityName = selectedObject.Name;
[self.navigationController pushViewController:view animated:YES]; [view release]; }
The ‘Name’ error confuses me because I know the City entity has a Name property.
In TestView.h I use this code:
@property (nonatomic, retain) NSString* CityName;
is this correct? at first I tried NSString *CityName; but I don’t know what the difference is (yet I receive no errors here either way).
Under the section
@interface TestView : UIViewController {
Do I need to write any code? For example
@interface TestView : UIViewController {
NSString *CityName;
// below is the code I am using to connect to my UILabel
IBOutlet UILabel *cityName;
}
Thanks for taking the time to help out – I hope this can help others, too.
Joshua Lund
July 14th, 2009 at 7:59 pm
Sorry, my code got scrambled when I pasted it in here – here is a (hopefully) clean version:
if(self.entityName == @”County”)
{
// Create a new table view of this very same class.
RootViewController *rootViewController = [[RootViewController alloc]
initWithStyle:UITableViewStylePlain];
// Pass the managed object context
rootViewController.managedObjectContext = self.managedObjectContext;
NSPredicate *predicate = nil;
NSManagedObject *selectedObject = [entityArray objectAtIndex:indexPath.row];
if(self.entityName == @”County”)
{
rootViewController.entityName = @”Province”;
// Create a query predicate to find all child objects of the selected object.
predicate = [NSPredicate predicateWithFormat:@"(ProvinceToCounty == %@)", selectedObject];
}
[rootViewController setEntitySearchPredicate:predicate];
//Push the new table view on the stack
[self.navigationController pushViewController:rootViewController animated:YES];
[rootViewController release];
}
else if(self.entityName == @”Province”)
{
TestView* view = [[TestView alloc] initWithNibName:@”TestView” bundle:[NSBundle mainBundle]];
// without the code below, I would get an error: ’selectedObject’ undeclared
NSManagedObject *selectedObject = [entityArray objectAtIndex:indexPath.row];
//with the above code in place I now get the error: request for member ‘Name’ in something not a structure or union
TestView.CityName = selectedObject.Name;
[self.navigationController pushViewController:view animated:YES];
[view release];
}
Björn Sållarp
July 14th, 2009 at 9:45 pm
My bad, I was at work and just wrote the code out of my head. Becuase it’s CoreData you must get the Name property from the object using: [selectedObject valueForKey:@"Name"]; , just like how it’s done when rendering each item in the table view.
You should be all good now
. Peace!
Tony Hung
July 15th, 2009 at 4:07 pm
Awesome Tutorial! I’ve been looking for something like this for a long time! Is it possible to parse the xml but don’t store it in the Database? I only need the xml loaded for the current session. Is there an easy way to do this?
Björn Sållarp
July 15th, 2009 at 4:46 pm
Thank you.
Of course! Instead of storing the values in CoreData you can create own “normal” classes to hold the parsed information. Add a mutable array property in the xml parser and store your objects there during parsing. Then you can return that array to your app when you are done.
The trade-off is that all your data must be held in memory all the time and you can’t search your data as simple as with CoreData (sqlite). But if you only have a small amount of data that’s not a big deal really.
If your app depend on the data in may different views I suggest that you create a singleton object that hold the parsed data. That way you can easily access it from anywhere in your application.
iPhone - Tips for building great server/client apps | blog.sallarp.com
July 15th, 2009 at 11:33 pm
[...] by using the objectForKey method of the dictionary. I’ve implemented this technique in my CoreData example app. While XML is an excellent markup for structured data it does provide quite a bit of overhead. If [...]
Ruhi
July 16th, 2009 at 9:50 am
Hey! I don’t know if you have the time. But i really have looking for someone to explain how to sort an NSMutableArray in a table view alphabetic, just like Native adress book. I have been looking at app doc and samples, but i just don’t get it.
I have parsed my data from an XML into my array. And then??
Joshua Lund
July 16th, 2009 at 7:00 pm
Alright, you must be getting sick of me by now… I just can’t work this out. My code looks like this:
else if(self.entityName == @”Province”)
{
TestView* view = [[TestView alloc] initWithNibName:@”TestView” bundle:[NSBundle mainBundle]];
NSManagedObject *selectedObject = [entityArray objectAtIndex:indexPath.row];
TestView.CityName = [selectedObject valueForKey:@"Name"];
[self.navigationController pushViewController:view animated:YES];
[view release];
}
But I get two errors on the TestView.CityName line: accessing unknown ’setCityName:’ class method
and
object cannot be set – either readonly property or no setter found.
I imagine this is something wrong in TestView.h
The relevant parts of this are as follows:
@interface TestView : UIViewController {
IBOutlet UILabel *myTextLabel;
NSString *CityName;
}
@property (nonatomic, retain) NSString *CityName;
@property (nonatomic, retain) UILabel *myTextLabel;
-(NSString*) CityName;
// Not sure about the code below, I added it (and accompanying code in TestView.m) in a desperate attempt to get it working
-(void) setCityName:(NSString *)cityValue;
@end
Any idea what I am doing wrong? I’m quite over my head here. Thank you very much, Björn. You have been a tremendous help!
Do you have any apps in the app store I can purchase to thank and support you?
Björn Sållarp
July 16th, 2009 at 7:25 pm
@Ruhi, if you are reading the data from your own source you could sort it there instead. But sorting an array isn’t that hard, check out this forum thread: http://www.iphonedevsdk.com/forum/iphone-sdk-development/3480-sorting-nsarray.html
@Joshua, Looks like you are almost there! When you define a property in your interface (.h file) you must synthesize it. Add this to your .m file: @synthesize CityName;. Look at my RootViewController for an example. What synthesize does is to create the get and set method for you at compile time. You should remove:
-(NSString*) CityName;
-(void) setCityName:(NSString *)cityValue;
The only app I have on the store is free, I’m not doing this for money. I suggest you spend some money on a book instead, I started with zero knowledge about Obj-C and read this one: Cocoa Programming for Mac OS X by Aaron Hillegass. It’s not written specifically for iPhone development but does a great job explaining Obj-C in general.
Joshua Lund
July 16th, 2009 at 7:52 pm
Oops, I forgot to mention @synthesize – I have been synthesizing CityName all along, so the problem isn’t there. I added
-(NSString*) CityName;
-(void) setCityName:(NSString *)cityValue;
after initially getting those error messages, hoping it would help… but alas, it did not. I deleted those two lines and the errors persist.
So you think the code looks right? I tried re-typing this part of the code, just incase I am having the same random issue as before, but it didn’t help.
Maybe I’ll start over from scratch and see if I can get it working from the top…
Thanks again.
Björn Sållarp
July 16th, 2009 at 8:20 pm
It looks fine as far as I can see. Unless your project is super secret you can E-mail me your code and I can take a look. you find my email on the “about me” page.
Ruhi
July 17th, 2009 at 9:46 am
Ok Yeah, i managed to sort the array now. But i want them to be in different sections (A, B, C..). So how do I sort all that begins with “A” in section “A” and how do I know how many rows it should be in every section.
Sorry for having a hard time understanding
Doug Allison
July 17th, 2009 at 4:03 pm
Just wanted to say MANY MAY Thanks, been looking all week on how to handle this kind of thing in an App I am working one. To say the least what is out there is limited and mostly confusing to me (newbie). I stumbled on this post and codes snippet and it is a god send .. many thanks.
Ethan
July 17th, 2009 at 8:17 pm
@Björn Sållarp
Was Joshua Lund’s problem ever fixed? I have this same issue, I need to take data from the xml and display it on a detail page. Would you be able to write up a little Core Data based drill down menu (drill at least 3 times) and at the very end have a detail page? That would be greatly appreciated by everyone here.
Thanks!
Björn Sållarp
July 18th, 2009 at 9:47 pm
@Ethan, Yes, Joshua got his app to work. I’ve updated the example with a details page, enjoy!
@Ruhi, You’ll have to do that by looping through the array. I’m pretty sure Apples TableView example does what you’re looking for.
sigar
July 21st, 2009 at 11:56 am
Hi
Thanks for this tutorial.
I wonder what I have to do if I had two different sqlite DB-Files, one with customizable data and one with independent data (different entities in different files).
I understand that loading the models always merge all model-files. But I like to have different model-files and different persistent store files in one context.
I found a function that assigns a specific persistent store file to a managed object. All in one context which I like because the customizable data and the independent data are connected through relationships.
But I don’t get it work.
Can you help me on this? Or can you give me an example?
Is there a way to create different sqlite-files which have only assigned entities within one context?
many Thanks.
Andy
July 23rd, 2009 at 12:33 am
Thank you for this post and good discussion thread.
I am trying to build an app that will have an initial load of data from an XML file such as yours but will need to be edited by the user. To some extent like a contact manager where the user can drop/add/edit/rearrange some of the fields (‘counties’, ‘provinces’ and ‘cities’) and then enter his/her own detail (inhabitants, desc, etc.)
So I need help in knowing how to persist the changes and how to make each of the two views editable in the usual iphone ways.
Is this possible? Feasible?
Thanks for any guidance!
Björn Sållarp
July 23rd, 2009 at 12:41 pm
@sigar:
I’m pretty sure it’s impossible to have data stored in different databases and set up relationships between them. I don’t know of any SQL database that can do this. Relationships depend on knowing that data exist, and there’s no way of knowing for one database what’s in a different database.
I can’t see a reason to why you want to separate the databases but you probably do. One way of achieving that would be to handle the “relationships” in code. Say you have data in one database and the objects there have at least one unique id each. In your other customizable database your objects has a property which isn’t a relationship but you set a value there which exist as a unique value in the static database. This will act as your “relationship” to the static database. It will however require you to write a lot more code and could become a problem if an item in the static database is removed etc.
If I were you I would re-think the whole idea of physically separating the data when they need to reference each other.
@Andy:
That’s absolutely possible. Check other samples about editing/adding data to a table view. I know Apples core data sample contains an add-function.
The easiest way to keep the data consistant on both server and client app is to send the changes to the servern and only if that returns OK you save the changes to your core data store. Alternatively you could allow the user to make changes and then push a button to upload all data to the server.
If changes are first sent to the server that will require constant internet connection to edit/update in the app. Having a save-button enables offline editing but if the data can also be changed elsewhere you could get inconsitancey issues if items are removed on the server and the client doesn’t know about it and again adds it to the server etc.
Rob
July 28th, 2009 at 7:31 pm
Great Tutorial and thanks for taking the time. A question I had was one step further: How to add a clickable “Telephone number ” Label, a “Map” button with the UIMapKit and an “Email” link all from your DetailViewController, under the ‘description’. Presumably there is a way to connect it all with the Locations.SQL database. Many thanks if you can figure it out…
Björn Sållarp
July 28th, 2009 at 9:56 pm
Thanks Rob!
You can create a clickable phone number by making a URL that start with “tel:”. Here’s an example of how to make a call by pressing a button in the app. Bind this method to the buttons click event:
-(IBAction)phoneClicked:(id)sender
{
NSString *callPhone = [NSString stringWithFormat:@"tel:%@","+46709999999"];
NSLog(callPhone);
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:callPhone]];
}
For email you should use the in app email functionality in 3.0. Look for MFMailComposeViewController. Here’s an example of how you can pull up a modal in app email composer. to your views interface declaration, example:
Add
@interface MyViewController : UIViewController
Methods for opening the mail dialog:
NSString*)mailBody
BOOL)isHtml
- (void)openInAppEmail:(NSArray*)recipients: (NSString*)mailSubject
{
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setToRecipients:recipients];
[controller setSubject:mailSubject];
[controller setMessageBody:mailBody isHTML:isHtml];
[self presentModalViewController:controller animated:YES];
}
Method for closing the dialog.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[self dismissModalViewControllerAnimated:YES];
}
Fairly simple. Apple has sample apps for this.
The map control is also pretty easy to use. Check the samples from apple.
Good luck!
Randy
August 6th, 2009 at 12:22 am
Great post thanks!!
asusual
August 6th, 2009 at 11:06 am
Perfect tutorial!! You really help me to build my first application. I am trying to add one more entity like “town” under city. So when you click city it’ll go to town rather than inhabitants and description. I am noob so I could not figure it out. Can you show me a guideline how to do it. Thanks in advance.
Kas
August 11th, 2009 at 4:36 am
Thank you for the very helpful tutorial. I’ve noticed that sometimes when I scroll the County table, the disclosure indicator appears in cells that it should not be in. Do you know what causes this or how to fix it?
links for 2009-08-11 | Alones world
August 12th, 2009 at 2:29 am
[...] iPhone – Core Data and UITableView | blog.sallarp.com pre population usign XML (tags: tutoiral iphone_dev coredata prepopulated iphone_problem) [...]
valerio
August 18th, 2009 at 7:34 pm
Great Tut …I just download the sample project but when I run it i the 3.0 simulator doesnt work well ..it just load the first country table …I missing something…??? Your help will be great..
jverner
August 26th, 2009 at 6:43 am
An excellent and clear how-to manual for using Core Data. But of course, I have a question: How does one format within the xml desc field? Bold face, paragraph breaks and the like. Html didn’t work for me.
silverpie
August 27th, 2009 at 5:40 pm
HTML codes are the right way to go, but what may be the issue (reading this on a Windows box, so can’t check) is that the city may be getting displayed in a UITextView–it needs to be a UIWebView to enable formatting.
Mark
October 9th, 2009 at 10:28 am
Hi,
First of all, thank you for a great tutorial. It’s really helped me get my head around some fundamentals of building for the iPhone.
A couple of questions though. When viewing the detail page for a city I would like to be able to have the ability for some pages to just have text, others to include images and others to include video clips. How can I achieve this?
Also, is it possible for each menu item to have an icon beside the title?
Hope I’ve explained this properly.
Many thanks,
Mark
Eşref Atak
October 10th, 2009 at 7:30 pm
Is it very useful example. I change the project for my needs.
Thank you.
vg
October 16th, 2009 at 9:04 pm
thx for the great tuorial. I am stuck at one point. First the Xml is loaded in the database. With next start of the application i would like to load the data from the database. though data is stored in the “location.sqllite” but core data helper doesnt return any result.
any idea..
cheers
Stephen Aiena
October 21st, 2009 at 3:32 am
This tutorial gave me a great start, but I’ve run into a problem with my project.
My table is populated with the first level of my data hierarchy, but when I select a table row, and the CoreDataHelper searchObjectsInContext method is called, the NSEntityDescription entityForName method consistently returns a null value (so the subsequent fetch request fails). I’m passing the correct entityName and managedObjectContext.
Does this failure indicate a problem with my Data Model?
Stephen Aiena
October 21st, 2009 at 7:33 am
Arghhh! Please ignore my previous post. I had a typo in my code.–I was looking at it for 3 days and didn’t see it ’til now.
Stephen Aiena
November 18th, 2009 at 1:10 am
I have a scenario in which a user enters a string. I then need to search the managed object for the first occurrence of the string in the Name property of the Province entity and return a list of related cities for the matched Province. Can this be done with a single call to searchObjectsInContext and if so, what would the predicate look like?
Rob Mathews
December 22nd, 2009 at 10:48 pm
Has someone worked through enabling functionality for “heightForRowAtIndexPath” using the current source code. If yes, please post the changes/updates that need to be made.
Hilton
December 23rd, 2009 at 3:49 am
Rob, I have as early as today requested same/similar from Bjorn, via email.
I will post any response when received. Thanks.
omar
December 28th, 2009 at 11:57 am
HI Björn Sållarp,
your example is very useful. i really thank you because i understood how to use core data. Now i have a big problem. how to add a tabBarController to your example (to manage different view) without get an error??? i tried in many ways but every time i got an error in the coredatahelper and i don’t know why….
i just put in the mainwindow.xib the navigation data inside a new tabbarcontroller, linked it with the coredatatestappdelegate.
inside coredatatestappdelegate.h i created the variable UITabBarController *tabBarController;
and the property @property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;)
in the coredatatestappdelegate.m i just put @synthesize navigationController,tabBarController;
and in the -(void)applicationDidFinishLaunching:(UIApplication *)application function i put [window addSubview:[tabBarController view]];
i think is correct but it give me an error.
please help me.
thanks
Leili Farzaneh
December 30th, 2009 at 1:59 am
Thanks for this really helpful tutorial. I’d like to create an A-Z index for the country, with the data grouped into sections by first letter… could anyone give me a point in the right direction for this? I have looked at *every* source code, tutorial, etc online but can’t work out how to apply it to this example!
Many thanks in advance, Lx
Stephen Aiena
January 14th, 2010 at 12:40 am
Instruments is reporting a memory leak at this line:
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
If I understand correctly, the subsequent “return mutableFetchResults;” leaves an unreleased copy of mutableFetchResults.
Any advice?
John Meyer
January 18th, 2010 at 2:59 am
Hey, great tutorial! However, when I try to run the source code, I can click through one table view cell, but than when it goes to the next table view, there is nothing there. Is there something wrong with this updated source code, or can I fix it myself? Thanks again for this tutorial; it is exactly what I have been looking for.
Peter Jones
January 23rd, 2010 at 6:33 pm
Beautiful code. Thanks for sharing.
duh
January 23rd, 2010 at 11:06 pm
Good job, but I get the feeling that something is missing from this tutorial. Like how to persist data and not load from the xml each time? Isn’t that’s what core data is really for?
Björn Sållarp
January 24th, 2010 at 5:59 pm
@Duh. Depends on your application I guess. The scope for this sample was loading data into the model and present the data in a uitableview. Of course you probably won’t load data from a static XML file each time in a real application, but this is just a proof of concept application.
Another tutorial extending this example with the ability to add data is something I will consider. Unfortunately I only have so much time…
Almeist
January 28th, 2010 at 8:14 am
Thank you for your tutorial. I have managed to customize it into what I hope will be my first App.
I have successfully gotten rid of the first level of Drilldown leaving two levels, State and Place.
I have changed the names of entities and attributes so that the Place entity has attributes Name, Address, and Description.
I have edited the xml file to have all the relevant info that I want and I have it working, and for this I am very grateful.
There is just one more thing that I would like to add to this and that is an image in the detail view. That is, each ‘Place’ has its own image that shows up in the detail view when you drilldown to that ‘Place’.
The images would be pre-built into place and there is no need for user editing or anything like that.
I have bought books and have scoured the internet but cannot find how to store images in the Application, and have them show up in the detail view. (different image for each ‘place’). Ive been doing the trial and error thing but am getting nowhere with it. I am assuming you need to store something in the xml file and have the seperate images in the Resources Folder but I cannot get any further.
I would be greatly appreciative if you could help me out with this. Even if you modified you Example code to include an image in the detail view I could take it from there.
Cheers Al.
Björn Sållarp
January 28th, 2010 at 8:27 am
@Al,
I’m happy the code was of use for you. If you want to bundle the images with the app, place them in the application bundle. In the XML, add an attribute with the name of the image so you know which one to load. Then use this line to actually fetch the image:
UIImage *img = [UIImage imageNamed:@"imagename"];
Replace the string with the variable containing the image name from the XML/DataObject. Then set the UIImage to your UIImageView. If you want to see some code have a look at my scrollview demo: http://blog.sallarp.com/shouldautorotatetointerfaceorientation/ I load the images from the application bundle there.
If you want to load your images from the internet, place an internet url in your XML and have a look at my post about downloading images asynchronously: http://blog.sallarp.com/asynch-uiimage-revisited/
Good luck with your app!
Cheers!
Almeist
January 29th, 2010 at 7:17 am
Thank you so much for getting back to me.
Can I just clarify some things.
When you say”In the XML, add an attribute with the name of the image so you know which one to load.”
Do you mean – Add an attribute to the xcdatamodel of type string and then add the extra data in the xml file like this:
And if so would that mean that the line to fetch the image would read:
UIImage *img = [UIImage imageNamed:@"pimage"];
I assume that the images should be copied into the Resources Folder in XCode. I noticed in your scrollview demo that the images were in there own folder called “Images” in the Resource Folder. Does that make a difference?
I greatly appreciate your help on this.
Cheers Al.
Almeist
January 29th, 2010 at 8:02 am
Hi Again,
It appears that some of my previous post didn’t turn up. I must have used illegal characters.
What I meant to say was
Do you mean – Add an attribute to the xcdatamodel of type string called “Pimage” and then add the extra data in the xml file like this:
State
Place name=”Blah” desc=”blah blah” pimage=”PlaceImage1.jpg”
Place name=”Bing” desc=”bling bling” pimage=”PlaceImage2.jpg
State
Also I am having trouble working out where to use the line to fetch the image.
There are a few places where the other attributes are called, like in Place.h there is
@property (nonatomic, retain) NSString * Address; etc
and Place.m has
@dynamic Address etc.
Locations Parser.m has:
c setAddress: attributeDict objectForKey:@”address” ; etc
and DetailsViewController.h has:
@interface
…
IBOutlet UILabel *addressLabel;
…
NSString *address;
@property UILabels and NSStrings
and DetailsViewController.m has:
@synthesize’s and
self.addressLabel setText:self.address as well as releases
These are all for the “address” attribute as well as the same for the other atributes “name”, “desc”.
Am I missing the point here. Is it as simple as using the line”
UIImage *img = [UIImage imageNamed:@pimage"]; somewhere.
Please forgive my ignorance but I feel I dont quite understand how to use your advice.
Thank you once again for spending the time to help me.
Cheers Al.
Omar Scott
February 11th, 2010 at 9:45 pm
I see you code grabs xml from the local directory, however what if it is a public domain, how can I handle that….?
I want read in an xml feed parse store its data, then display the data in a table view.
Can I do this and if not what would be the alternative
Jamie
February 13th, 2010 at 1:05 am
Great tutorial! Also, thanks for posting the detail page, exactly what I was after. Now off to (hopefully) integrate tabs and a map…
Manuel
February 15th, 2010 at 5:09 pm
Hi Björn Sållarp,
First of all, thanx for the example with this tutorial it really had heklped me to understand how coredata works. I have been working on an app which displays a text document from a selected category, and have found your tutorial very usefull, however I have a bit of a problem when I display the data in the xml file. I´m a newbie in iphone development and perhaps this is a stupid question but it had me looking around over the web for an answer: how can I make a carriage return or line break when a paragraph ends in my document, because even as the document has several paragraphs it is displays as a single one. I have tried tags like br, used in html but with no result.
Hope you can help me out on this one, and sorry if it is a kinda stupid question, I´m a newbie on iphone dev and xml.
Thanx in advance
Chris
February 17th, 2010 at 1:26 pm
Hi great tutorial, followed it through and learnt quite a bit! I am now trying to create my own app that uses 2 entities one below the other such as country and province in this example. I have tried using very similar code to do this and i have the table for the first entity appearing fine, when i click on a cell containing an object from the first entity the table that appears should contain all the other entities related to the first entity however the table is blank. I have checked the sql database and it does contain all the data from the xml file so the parser isnt the problem, but i cannot find what is causing the data not to be displayed in the table, any ideas would be greatly appreciated, if you need i can send my project. Many thanks !
Björn Sållarp
February 18th, 2010 at 8:03 am
@Manuel,
If you want to easily format your text, swap the UILabel for a UIWebView instead and user HTML to format the description.
@Chris
Did you rename the entities? I think your problem is in the RootViewController, function: didSelectRowAtIndexPath. That’s where the data is fetched from the database. Make sure the entity names match your model. If you can’t manage to fix it, send me the code and I can have a look.
Andrei
February 27th, 2010 at 10:45 am
Hello,
this is a great tutorial and I’m working at an app that have as starting point this tutorial. But I have a problem when I try to add a search bar. How can I filter the array by searchText and display the array on tableview?
What I have managed to capture search text but I can’t display the new filtered `array.
Manuel
March 3rd, 2010 at 7:31 pm
Thanx Björn,
I have figured how to do this text formatting in the XML, I found that using the “
” (without the ” “) at the end of each paragraph would work as a “carriage return” with a Tab also. Anyway i´m gonna try the UIWebView instead of UILabel to see how things work out. Thanks again for your advice.
I have another question, If it is not much of a trouble for you: how can I add a little image at the left of the title in each tableviewcell and how would I link it to the XML file to assign each to the appropiate cell. I have read I would have to use imageView but can´t seem to understand how to do it with an XML document.
Thank you in advance
nerdfont » Blog Archive » iphone development: part 2
March 15th, 2010 at 5:42 am
[...] A large area of debate when dealing with tables is data storage. I have looked into both XML and Core Data, of which there are many sites that discuss the pros/cons of these two types. In terms of displaying data stored in either XMl or Core Data in a table, these sites have been useful in learning how to parse the information into table cells. For XML, I used Apple’s documentation (http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ XMLParsing/Articles/UsingParser.html) to learn the process of extracting the data desired. For Core Data, I found this website very helpful in discussing the process of using Core Data for tables: http://blog.sallarp.com/iphone-core-data-uitableview-drill-down/. [...]
Martyn F
March 22nd, 2010 at 11:23 pm
Björn,
Thank you so much for this tutorial. After spending several days trying to figure out how to use core data with multi-level drill-downs and getting nowhere in the process… your tutorial has saved my sanity. Wish I’d found it earlier,
Keep up the great work. Thanks again.
Peter
March 26th, 2010 at 5:30 am
This is great. Thank you for sharing this.
Suman
March 28th, 2010 at 9:18 am
Hi, I am looking for code for your “iPhone scrollview image gallery” app. pls. send me the link or file. Thanks a ton.
Armindo
March 31st, 2010 at 9:57 am
Björn,
As Stephen Aiena said previously, if you try “build and analyse” you will see some memory leaks in CoreDataHelper class…
Any idea of how to fix this ?
Thanks
Björn Sållarp
April 3rd, 2010 at 12:24 pm
Thanks everyone for the great feedback. This is by far the most popular post on my blog. I’ve updated the post and code sample today. Xcode reported three warnings when analyzed, they have been fixed. I’ve also added in app email and phone functionality to the details page.
Happy easter everyone!
// Björn
Abdolhosein Vakilzadeh Ebrahimi
April 5th, 2010 at 9:04 am
Thanks for simple sample.
Hedi
April 20th, 2010 at 5:55 pm
Hi thx for this great job.
Just a question :
How can i remove 1 level for exp : province .
Christian Winter
April 28th, 2010 at 7:43 am
Hi great Tutorial! It helped me a lot. But what if i have in my DetailView a Button and when i press the Button it loads another View. How can i there access the data stored at the start of the application?
Björn Sållarp
April 28th, 2010 at 5:17 pm
@christian
You can access the data in your new view just like in my sample app. Read up on core data and look at my code how data is read from the data model. It’s pretty simple.
Good luck!
Harinder Singh
May 5th, 2010 at 11:06 am
Thanks for this great tutorial. It is really helpful
Christian Winter
May 11th, 2010 at 9:22 am
Thx Björn this worked, but now i have a new Problem. One Part of my App is TableView Nav-based like yours and there is also a one-to-many relationship organisations to brands. Everything works in tableview. When i touch the cell i get the brands of an organisation. My Second View i can start at my MainMenu Page is a MapView. There it shows me the location of all Organisations. When i touch the pin i get my annotation subview with a Show Brands button. Of course i only wanna show the brands of that Organisation.
My problem is that at the first part i have the NS Predicate predicate1 = [NSPredicate predicateWithFormat:@"(BrandsToOrg == %@)", selectedObject];
But at the Mapview i have an EntityArray and a Property like TitleMedium (name of my Organisation).
i tried predicate1 = [NSPredicate predicateWithFormat:
@"ANY org.TitleMedium like 'myOrgName'"];
this doesn’t work.
Any idea?
cheers
Davy
May 17th, 2010 at 5:55 pm
Björn,
Thanks for a great tutorial! I’ve been trying to place the navigationController inside a TabBarController. I’ve been successful in making the TabBarController the rootController for the App. However, I can’t get it the addSubview to show the new rootController.
If possible, can you share how to edit this tutorial to have the navigationController appear inside a TabBarController?
Thanks in advance for your help.
Fred
May 18th, 2010 at 12:29 pm
Hi,
Thanks for a great tutorial. One thing I can’t figure out – I’m a noob and have been through the code and googled galore – how do you change the titles from county / city/ etc. i thought this would be simple, but I can’t get it working. I have used self.title to change the title to something else, but that then stays the same throughout the app.
So my Q: How do you change the titles?
Thanks again
F
john
May 20th, 2010 at 1:33 pm
Hi,
Looks great! I’ve got a question though, could you show me how to change this app in such a way that city-screen (arjeplog) is an on the iphone, no internet needed, stored html file?
I’d like to build something like this but then with graphiccally rich pages (html-formatting, pictures, links etc)
Thanks for the great tuturial!!!
John.
Björn Sållarp
May 20th, 2010 at 11:39 pm
@John,
If you want to present fancy formatted text, create the HTML pages and add them to your app. You can then use the uiwebview to display a HTML file from your application bundle. Good luck!
John
May 21st, 2010 at 9:48 pm
Hi Björn,
Thanks for your reply. I think that I’m way over my head here, but I really like to understand how it all works and fits together.
Would it be to much trouble to show me how to do this in an updated source file?
I learn better by looking how it’s done and than imitating and adapting it, than by telling what road to take and figuring out how. One typo or wrongly linked view and the whole thing won’t compile
John Draper
May 22nd, 2010 at 11:22 pm
Where can I download this Core Data Sample App. No link was given on this site.
Please also send reply to:
jdcrunchman at gmail dot com I dont come here that often!
John Draper
May 22nd, 2010 at 11:28 pm
Never mind – I found the link… My eyes are really getting very bad.
Will
June 9th, 2010 at 3:12 am
How would I go about adding/deleting/rearranging items in each table then saving to the XML. Thanks!
Richard
June 9th, 2010 at 3:38 pm
Hey Björn,
Great tutorial – I’ve been looking for something like this.
I just tried downloading the sample code and running the app on the simulator and the device but when I click on any county, the province list is blank and I can’t go any further. Is there something wrong?
Björn Sållarp
June 10th, 2010 at 8:47 am
@Richard. Look in the XML file. It doesn’t contain values for all levels.
// björn
Alex
June 10th, 2010 at 11:02 pm
Superb tutorial! I’ve spent hours days looking for something like this so thank you.
Any suggestions for making this work on the left rootviewController of a Split View based app on the iPad?
Thank you
Richard
June 14th, 2010 at 12:23 am
Thanks for replying Björn.
Sorry about that – I just assumed that the XML file was fully populated. I didn’t notice the disclosure indicators on the entries that do contain values either.
Thanks again for the great tutorial also.
Ian oh
June 25th, 2010 at 7:02 pm
Great tutorial.
I try to change the XML name for county,province,city into
Province,prefecture and county, I even changed all the source code, data model, when compile there are no syntax problem, but the debug console say addProvincetoPrefecture object problem.
The sqlite files doesn’t exist so I think the XML parser didn’t go through
Did I miss anything? Thanks.
Aleks
June 30th, 2010 at 2:19 pm
I downloaded your little DrillDown style iPhone app and had some questions.
I’m trying to make a background show up so that when the Table doesn’t have a full screen of cells you can see it.
I set the background in the MainWindow xib but cannot get the table to become smaller…
I am also trying to eliminate the ‘city’ screen (the one that shows a list of cities before showing the detail view) essentially i want it to go from province strait to detail view.
How would that be accomplished?
Lastly.
I changed it to use a remote xml file instead of the local data.xml. It crashes if it doesn’t get a network connection though. Do you know what even I have to trap to get it to use a local file if there is no network connection?
Any insights would be really cool!
Ivan
July 3rd, 2010 at 10:35 am
This is a great tutorial!
How come you don’t use NSFetchedResultsController to populate each level of UITableView? How could the code be rearranged to do it using NSFetchedResultsController? Would every level have to have it’s own view conroller and it’s own NSFetchedResultsController? Thanks!
Jake
July 8th, 2010 at 9:05 am
Hi Björn Sållarp,
Thank you for the great tutorial!
I followed through and downloaded the sample project that you have given. I have only changed the values of the xml file and only placing values in labels for my DetailsViewController.
I have been able to retrieve the values from xml but unable to retrieve them from the NSEntityDescription portion.
This is the error that is shown in my console:
2010-07-08 15:00:58.554 StaffDirectory[1000:207] *** -[Staff Name]: unrecognized selector sent to instance 0×200d2f0
2010-07-08 15:00:58.561 StaffDirectory[1000:207] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[Staff Name]: unrecognized selector sent to instance 0×200d2f0′
2010-07-08 15:00:58.565 StaffDirectory[1000:207] Stack: (
807902715,
2426455305,
808284155,
807854166,
807706786,
18303,
811133086,
7450485,
7465080,
811130623,
17053,
9388,
814713539,
814750709,
814739251,
814722434,
814748641,
839148405,
807687520,
807683624,
814715661,
814752238,
9032,
8886
)
Build was successful but the app just crash when it try to get the DetailsViewController. By the way, i changed the entities to match my xml for example; “City” to “Staff”.
PS, I’m very new to Objective C and this is my first few projects that i have tried. Can you please help me take a look at this?
Thanks!
Ron W
July 8th, 2010 at 5:13 pm
1st of all…thanks for the great sample, it is a great one.
2nd……….I see that the ScrollView is sized by calculating the description field. This is fine for a Portrait view, but is not good for a Landscape view. Can you please pass a snippet on to me that will remedy this? I hope to not have to create a LanscapeViewController just for this. I am thinking somewhere in the “- (BOOL)shouldAutorotateToInterfaceOrientation:” section would be the spot for this type of action.
Thank for all the great info you have shared with all of us,
Ron W
Björn Sållarp
July 8th, 2010 at 7:52 pm
@Ron, yes shouldAutorotateToInterfaceOrientation is the place. In that method you can just resize the elements you want. Return yes (to rotate) but before you return yes, use the same method to calculate the new height for landscape width.
// Björn
Björn Sållarp
July 8th, 2010 at 7:57 pm
@Jake
You say you updated the entities. Did you update the model file and also the matching .h/.m files for each entity? Sounds like maybe you just updated one of them.
// Björn
Ron W
July 9th, 2010 at 3:47 am
Yes Bjorn, I have set the Autorotate code in place, but the context width does not widen to the landscape size. Can you help me with this frame.width modification? It seems to be connected to the descriptionframe size. I am not succeeding in getting this right. PLEASE help!!!!. The top coordinate appears to need adjustment as well. I am studying CG settings to see what I can do in the meantime, but everything I do messes it all up.
Thanks for the fast response earlier. I appreciate the help.
Ron W
Jake
July 9th, 2010 at 6:06 am
Thanks Björn for the response, i changed the names of the entities. And updated the model file accordingly too. But it just keep returning the same error of not being able to read the “Staff Name”.
After several attempts, i have narrowed the portion of the error to the following code i have.
else if([elementName isEqualToString:@"Staff"])
{
Staff *s = (Staff *)[NSEntityDescription insertNewObjectForEntityForName:@"Staff" inManagedObjectContext:managedObjectContext];
NSLog(@”%@”,@”Before setting values”);
[s setName:[attributeDict objectForKey:@"name"]];
[s setEmail:[attributeDict objectForKey:@"email"]];
[s setPhone:[attributeDict objectForKey:@"phone"]];
[s setPosition:[attributeDict objectForKey:@"position"]];
[currentCourse addCourseToStaffObject:s];
NSLog(@”%@”,@”After setting values”);
NSLog(@”%@”,s.Name);
}
And this are the response i got from the console
2010-07-09 12:01:44.870 StaffDirectory[596:207] Before setting values
2010-07-09 12:01:44.871 StaffDirectory[596:207] After setting values
2010-07-09 12:01:44.872 StaffDirectory[596:207] *** -[Staff Name]: unrecognized selector sent to instance 0×161d610
2010-07-09 12:01:44.872 StaffDirectory[596:207] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[Staff Name]: unrecognized selector sent to instance 0×161d610′
2010-07-09 12:01:44.873 StaffDirectory[596:207] Stack: (
807902715,
2426455305,
808284155,
807854166,
807706786,
18269,
811133086,
7450485,
7465080,
811130623,
16985,
9320,
814713539,
814750709,
814739251,
814722434,
814748641,
839148405,
807687520,
807683624,
814715661,
814752238,
8964,
8818
)
I greatly appreciate the help, thanks again for the fast response.
Jake.
Ivan
July 11th, 2010 at 1:33 am
Hi Björn! This is a great tutorial!
How come you don’t use NSFetchedResultsController to populate each level of UITableView? How could the code be rearranged to do it using NSFetchedResultsController? Would every level have to have it’s own view conroller and it’s own NSFetchedResultsController? Thanks!
Tony
July 17th, 2010 at 4:25 am
Hi Bjorn,
Just want to say thanks for such a great tutorial and example code, its been a great help in getting me started in Core Data and building apps for the iPhone in general. I’ve managed to understand how most everything works in your example but I’m struggling with creating a detailed TableView. I want to add a thumbnail and description to the TableView but I can’t get to the data. I’m not sure how to go about it as the attribute data doesn’t seem to be available until the detail view is displayed, so I’m not sure where I should be looking. Grateful for any help you might be able to give me for this.
Ivan
July 17th, 2010 at 10:35 am
Tony,
try reading this http://petermcintyre.wordpress.com/2010/02/24/full-function-core-data-example-app/
Björn Sållarp
July 17th, 2010 at 10:53 am
@Tony,
Check out the samples from Apple. There’s a great sample showing how to efficiently add thumbnails to table rows: http://developer.apple.com/iphone/library/samplecode/LazyTableImages/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009394
// Björn
Tony
July 17th, 2010 at 1:43 pm
Hey Bjorn, Ivan,
Thanks heaps for the tips, I’m getting on them now to see if I can work it out. I’ve been trying for a while to get the data in where I want it but keep running into walls so I hope I can find a way through. I’m trying to get the extra data info from the detail view into the table view but its proving to be a problem so far. I don’t know if I have to add extra attributes at the second level or if I can just pull the data in from level 3; driving me mad at the moment. I can view the data from object in an array but I just can’t isolate it to use in the TableView. Very frustrating. Anyway, thanks for the links I’ll have a look and see what I can work out from there
Chris
July 22nd, 2010 at 11:52 am
Hi Bjorn. Thanks for your great tutorial.
I’ve used the guts in my application and its working well apart from memory leaks (with your new version).
There is an initial one, both in my app plus also your code – as can be seen if you run it with Performance Tools/ Leaks. As the sample is fairly simple, it gets away with it.
But on mine, as I reload the XML when requested (for an update check), it crashes after a few times.
The problem seems to be in Core Data Helper where, as far as I can see, mutableFetchResults is allocated but not released. I’ve tried adding it to an Autorelease pool, but it always crashes immediately then!
I’m still coming to terms with memory management (reading all that I can on it), so apologies if this is obvious to others.
Any help would be warmly welcomed.
Chris.
Björn Sållarp
July 24th, 2010 at 5:29 pm
@Chris,
The sample has been tested for memory leaks before I published it. It’s impossible to point out the leaks in your code from what you’ve posted, Core Data Helper returns an autoreleased array so there’s no leak there.
// Björn
Ron
July 27th, 2010 at 5:26 pm
I have modified and expanded on your CoreDataTest app sample, and I have successfully parsed data from my host site via XMLParser. The data is now in my Core Data Object on the phone. But the problem I have is that I would like to navigate to selected view controllers based upon the selection made (not just the one you have). I have worked with this for over a week now, and I cannot seem to get it right. If you would like to get my version of your app, please email me [ronbowalker@yahoo.com], or go to http://www.ihappyapps.com. I will try and park a link in there.
All help from you and others would be greatly appreciated.