Sebastien Peek
Sebastien Peek

Reputation: 2528

Adding Objects from an Array into Core Data

So, for the past two days or so I've been struggling with something that should honestly be a simple task. Here's a little introduction on what I'm trying to achieve.

What I'm doing is utilising a web service of my own, sending a request and parsing the returned JSON with SBJSON. What I know want to accomplish with this parsed JSON is to insert it into Core Data.

I have built a object model already which looks like the following:

#import <CoreData/CoreData.h>


@interface Event :  NSManagedObject  
{
}

@property (nonatomic, retain) NSString * summary;
@property (nonatomic, retain) NSString * content;
@property (nonatomic, retain) NSDate * updated;
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSDate * created;
@property (nonatomic, retain) NSString * ID;

@end

These are all built in regards to what is being parsed, I think I may have to change the NSDate's to NSStrings at a later date, but for now they are NSDates.

So, now to show you what is being parsed. The JSON returns the following.

[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"}, {"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"}, {"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]

What I am wanting to do is create an entity "Event" and each entity stores the respective values for that event. Easy, right? Obviously not for me.

What I have tried...

 NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

            NSManagedObjectContext *context = [appDelegate      managedObjectContext];

            NSManagedObject *newNote;

            newNote = [NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:context];

            [newNote setValue:[object valueForKey:@"note title"] forKey:@"title"];
            [newNote setValue:[object valueForKey:@"note summary"] forKey:@"summary"];
            [newNote setValue:[object valueForKey:@"note updated"] forKey:@"updated"];

            NSError *error;
            [context save:&error];

Yet this returns an error.

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "title"; desired type = NSString; given type = __NSArrayI; value = (
Car,
"Premium Users",
"Welcome!"
).'

Any ideas or code samples would help. I really need to get this fixed, all dependent on how this is being stored.

EDIT

Here's how we build the request and parse the string returned.

NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:@"api_key"];   

    [[LRResty client] get:@"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){

        if(response.status == 200) {
            NSLog(@"Pulling the users notes \n%@", [response asString]);

            // Create SBJSON object to parse JSON
            SBJSON *parser = [[SBJSON alloc] init];

            // parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
            NSDictionary *object = [parser objectWithString:[response asString] error:nil];

EDIT Just thought I'd let people know that I'm currently using the Resty RESTful framework to make my calls to my own API. I thought this was the best alternative and easiest way for myself to build a wrapper for it. Here is the full request. Resty documentation.

 -(void)pullNotes {

    NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:@"api_key"];   

    [[LRResty client] get:url parameters:params withBlock:^(LRRestyResponse *response){

        if(response.status == 200) {
            NSLog(@"Pulling the users notes \n%@", [response asString]);

            // Create SBJSON object to parse JSON
            SBJSON *parser = [[SBJSON alloc] init];

            // parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
            NSDictionary *object = [parser objectWithString:[response asString] error:nil];



            NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
            NSManagedObjectContext *context = [appDelegate managedObjectContext];
            NSManagedObject *newNote;

            newNote = [NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:context];

            [newNote setValue:[object valueForKey:@"note title"] forKey:@"title"];
            [newNote setValue:[object valueForKey:@"note summary"] forKey:@"summary"];
            [newNote setValue:[object valueForKey:@"note updated"] forKey:@"updated"];

            NSError *error;
            [context save:&error];

        }
        if (response.status == 404) {
            NSLog(@"FAIL\n%@", [response asString]);
        }

    }];

 }

EDIT

So, now that I have fixed the JSON issue and am grabbing the individual strings and such from each array, I'm having issues storing the parsed strings into Core Data.

I'll show you what I currently have.

[newNote ] is the name given to the Core Data entity in the header file of the following.

-(void)pullNotes {
 UIApplication *app = [UIApplication alloc];
    app.networkActivityIndicatorVisible = YES;

    NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:@"api_key"];   

    [[LRResty client] get:@"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){

        if(response.status == 200) {
            NSLog(@"Pulling the users notes \n%@", [response asString]);

            // Create SBJSON object to parse JSON
            SBJSON *parser = [[SBJSON alloc] init];

            // parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
            NSDictionary *object = [parser objectWithString:[response asString] error:nil];

            NSArray *notes = [object valueForKey:@"result"];
            for (NSDictionary *singleNote in notes){

                // newNote.created = [singleNote objectForKey:@"note created"]; Need to work on parsing these properly...
                // newNote.updated = [singleNote objectForKey:@"note updated"]; Need to work on parsing these properly...

                NSString *notetitle = [singleNote objectForKey:@"note title"];
                NSString *notesummary = [singleNote objectForKey:@"note summary"];
                NSString *noteid = [singleNote objectForKey:@"note id"];
                NSString *notecontent = [singleNote objectForKey:@"note content"];

                // NSDate *createdDate = 
                // NSDate *updatedDate =

                // If appropriate, configure the new managed object.
                [newNote setValue:notetitle forKey:@"title"];
                [newNote setValue:notesummary forKey:@"summary"];
                [newNote setValue:noteid forKey:@"ID"];
                [newNote setValue:notecontent forKey:@"content"];


                NSLog(@"value is %@", notetitle);

                NSError *error = nil;
                if (![newNote.managedObjectContext save:&error]) {
                    /*
                     Replace this implementation with code to handle the error appropriately.

                     abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
                     */
                    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                    abort();
                }


                [tableView reloadData];

                app.networkActivityIndicatorVisible = NO;

            }


        }
        if (response.status == 404) {
            NSLog(@"FAIL\n%@", [response asString]);
            app.networkActivityIndicatorVisible = NO;
        }

    }];

}

@end

However, running this code doesn't actually store the strings into the Core Data entity. As you can see it isn't finalised, a lot of commented code, but the basis is there. ANYWAY, I'm curious as to whether or not it is how I actually implement this in the pulling of the notes itself from the RootViewController...

In viewDidLoad() I'm calling the following...

 ntIndex = [IndexNotes alloc];
ntIndex.api_key = api_key;
ntIndex.tableView = self.tableView;
[ntIndex pullNotes];
[ntIndex release];
[self.tableView reloadData];
}

Any help would be great, I'd love to hear what others think the issue is. I don't get any errors with the above code, just nothing is inserted into the Core Data and in turn isn't displayed in my UITableView in RootViewController...

Upvotes: 2

Views: 3455

Answers (2)

Tim Davies
Tim Davies

Reputation: 834

It's to do with the fact [object valueForKey:@"note title"] is returning an array.

You'll like want to insert something more like [[object valueForKey:@"note title"] objectAtIndex:1] to take an object out of the array. However working out what index you want to insert from the title array is the hardest part.

Tim

EDIT: Having looked into some others responses its apparent it's returning all the titles in one object. There's something either incredibly funky going on with your JSON. A way around this would be to possibly for loop over your results set from your JSON request and using the index from this loop to insert the correct title.

eg:

int count;
for (count = 0; count < [[object valueForKey:@"note title"] count]; count++)
{
   // Do your other insert stuff here
   [newNote setValue:[[object valueForKey:@"note title"] objectAtIndex:count] forKey:@"title"];

}

again this is just a dirty example of what you could possibly do so solve this problem.

Upvotes: 0

rustyshelf
rustyshelf

Reputation: 45111

The first thing I would do is log what this line returns:

[object valueForKey:@"note title"]

You'll find it's not the string you're expecting, but is an array of note titles.

eg:

NSLog(@"value is %@", [object valueForKey:@"note title"]);

Then you'll either need to fix your JSON or change the way you parse it.

Edit: So when I say fix your JSON, I'm no expert, but I think it should look like this:

{"result":[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"}, {"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"}, {"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]}

Then:

NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NSArray notes = [object valueForKey:@"result"];
for (NSDictionary *singleNote in notes){
    [singleNote objectForKey:"note title"] //this gives you the title of the current note your on
}

Upvotes: 2

Related Questions