Another Paparazzi 2 Question

29 views
Skip to first unread message

Wayne

unread,
Mar 4, 2010, 2:42:21 AM3/4/10
to iPhone Application Development Auditors
This assignment is driving me crazy, perhaps the only thing keeping me
sane is the valuable insight from this group :-)

I have my PersonListViewController working, it can access the plist,
use Core Data to create and store the objects, and then fetch them for
the table view.

In my PhotoListViewController I have a person ivar, which is set when
I push this table view from the PersonListViewController. I verified
the person is being set correctly based on the user selection.

When I try to access the person's photos all hell breaks loose, here
is the code block:
NSArray *photos = [person.photos allObjects];
NSLog(@"number of items in array %d", [photos count]); // this returns
the correct count

// the following lines cause a crash
Photo *firstPhoto = [photos objectAtIndex:0];
NSLog(@"photo name %@", firstPhoto.name);

I don't understand what I am missing here... any help is appreciated.

Thanks,
Wayne

Wayne

unread,
Mar 4, 2010, 4:51:14 PM3/4/10
to iPhone Application Development Auditors
It is either a sign of insanity or discovery when you post the answers
to your own questions, in my case it's a bit of both :-)

I incorrectly assumed that Core Data was going to do some magic for
me. I assumed that if I had a Person object, I could just ask it for
its photos and get back the Photo objects, i.e.:
[person.photos allObjects];

What I got back was a bunch of garbled info, I assume (hopefully not
incorrectly again) that this is just information about the reference
relationship and not the object itself.

In order to achieve what I want, I had to another fetch where I get
all the Photos for the Person object I have.

Hope this helps someone,
Wayne

Kapsi

unread,
Mar 4, 2010, 2:02:07 PM3/4/10
to iPhone Application Development Auditors
Hi Wayne,
My guess is that it crashes because you sent a message (objectAtIndex:
0) to person.photos which is not an NSArray (despite your cast). The
side n of a 1-n relationship returns an NSSet which has no order. So
can't be accessed by objectAtIndex.

Kapsi

Kapsi

unread,
Mar 4, 2010, 4:04:19 PM3/4/10
to iPhone Application Development Auditors
Wayne: it should be because person.photos is an NSSet (the n side of a
1-n relation) and not an NSArray (even if you declare photos as an
NSArray). So when you try to send objectAtIndex, since NSSet has no
order, it crashes.

Kapsi

marcio

unread,
Mar 4, 2010, 9:18:23 PM3/4/10
to iPhone Application Development Auditors
Wayne

I too am getting this garbled info from logging the items array:

2010-03-04 20:01:17.254 Paparazzi[243:207] items array=(
<Photo: 0x1033a90> (entity: Photo; id: 0x1033290 <x-coredata://
DDA39EB0-5830-45C6-A21C-F79F696174C6/Photo/p1> ; data: <fault>),
<Photo: 0x1033ed0> (entity: Photo; id: 0x10332a0 <x-coredata://
DDA39EB0-5830-45C6-A21C-F79F696174C6/Photo/p2> ; data: <fault>),
<Photo: 0x1033fa0> (entity: Photo; id: 0x10332b0 <x-coredata://
DDA39EB0-5830-45C6-A21C-F79F696174C6/Photo/p3> ; data: <fault>)
)

Ive checked the data in the temp.sqlite file and its all there. Why
cant i log this array? And i guess because this is what i get, the
tableviewcontroller crashes when i set the indexpath.row to the
objectatindex for that array.

Wayne

unread,
Mar 5, 2010, 1:37:31 AM3/5/10
to iPhone Application Development Auditors
Marcio,

1. How are creating this array?
Hopefully you are using something like
[ marciosNSFetchedResultsController fetchedObjects] to instantiate
it.

2. How are you logging items from the array?
If you are doing something like NSLog(@"%@", [marciosArray
objectAtIndex:someIndex]), then you should get garbled results,
however if you ask each array item for its properties then you should
get the right data, i.e.
Photo *currentPhoto = [marciosArray objectAtIndex:someIndex];
NSLog(@"Photo name: %@, currentPhoto.name);

You should get what you are looking for.

Hope this helps,
Wayne

marcio

unread,
Mar 5, 2010, 10:05:56 AM3/5/10
to iPhone Application Development Auditors
No, im actually using the other method:

self.dataForTableView=[myConnection
fetchManagedObjectsForEntity:@"Photo" withPredicate:nil];

but ive also used this method:

NSFetchedResultsController *photosRC = [myConnection
fetchedResultsControllerForEntity:@"Photo" withPredicate:nil];

and i still get the garble. The problem was like you said, the way i
was logging the results. I got it now. So i guess I too was
expecting some magic to happen.

I guess this happens because the result of the fetch is an
NSFetchedResultsController object, but that means that with the
previous method it should work because that indeed returns an array.
Correct?

marcio

unread,
Mar 5, 2010, 10:27:01 AM3/5/10
to iPhone Application Development Auditors
i just did this:

NSFetchedResultsController *photosRC = [myConnection
fetchedResultsControllerForEntity:@"Photo" withPredicate:nil];

NSError *error;
BOOL success = [photosRC performFetch:&error];
NSLog(@"%@", success);
[self.dataForTableView = photosRC fetchedObjects];
Photo *currentPhoto = [self.dataForTableView objectAtIndex:0];
NSLog(@"Photo name: %@", currentPhoto.photoName);

but it still crashes saying

Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'keypath name not found in
entity <NSSQLEntity Photo id=2>'


Does photosRC fetchedObjects return an array? So it should be set to
another array and be fine...

Lenny

unread,
Mar 5, 2010, 10:45:52 AM3/5/10
to iPhone Application Development Auditors
Hi Wayne,

I'm not sure if I did it correctly, but it works. I think your issue
is that the relationship is expecting a NSSet of NSManagedObject
rather than an NSArray (as Kapsi mentioned). I can't tell, but I
think you are storing your list of photos in the relationship as an
array rather than just storing the image managed object into the
database.

I hope that helps.

Lenny

marcio

unread,
Mar 5, 2010, 10:52:40 AM3/5/10
to iPhone Application Development Auditors
I dont understand what you mean....this is how i store them:

NSArray *FlickrIds = [NSArray arrayWithContentsOfFile:filePath];
for (NSDictionary *dict in twitterIds){
Photo *newPhoto = (Photo*)[NSEntityDescription
insertNewObjectForEntityForName:@"Photo"
inManagedObjectContext:managedObjectContext];
[newPhoto setPhotoName:[dict objectForKey:@"name"]];
[newPhoto setPhotoURL:[dict objectForKey:@"path"]];
[newPhoto setOwnerName:[dict objectForKey:@"user"]];
}
NSError *error;
if(![managedObjectContext save:&error]){
NSLog(@"Error:%@",error);

The sqlite file stores them, ive seen the values in there.
photo1.jpg, josh, Leaves on Fire (or whatever :))

and this is how i retrieve them:

NSFetchedResultsController *photosRC = [myConnection
fetchedResultsControllerForEntity:@"Photo" withPredicate:nil];
NSError *error;
BOOL success = [photosRC performFetch:&error];

[self.dataForTableView = photosRC fetchedObjects];
Photo *currentPhoto = [self.dataForTableView objectAtIndex:1];


NSLog(@"Photo name: %@", currentPhoto.photoName);

Lenny

unread,
Mar 5, 2010, 11:16:00 AM3/5/10
to iPhone Application Development Auditors
Marcio,

Is that your whole code to store the data? You should also have a
Person entity with a 1-many relationship to your Photo entity, right?
Can I see the code where you did that? I think that is where your
problem lies.

marcio

unread,
Mar 5, 2010, 11:36:59 AM3/5/10
to iPhone Application Development Auditors
I havent gotten to creating the person objects yet, ive only gone thru
and picked out the photos. So yeah, thats all my store and fetch code
so far...

Lenny

unread,
Mar 5, 2010, 12:02:53 PM3/5/10
to iPhone Application Development Auditors
If this is all you have, then what is the type for "user" in the Photo
entity. Is it an entity or relationship? If all you have is 1
entity, then you can't set up a relationship.

Wayne

unread,
Mar 5, 2010, 4:46:16 PM3/5/10
to iPhone Application Development Auditors
Maybe you can try this to fetch the photos:

// setup our fetchedResultsController
fetchedResultsController = [flickr
fetchedResultsControllerForEntity:@"Person" withPredicate:nil];

// execute the fetch
NSError *error;
BOOL success = [fetchedResultsController performFetch:&error];
if (!success) {
// Handle the error.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1);
}


// save our data
[self setPeopleArray:(NSMutableArray *)[fetchedResultsController
fetchedObjects]];

Note, I am new to this but your line of code:
[self.dataForTableView = photosRC fetchedObjects];

looks wrong to me, it should be
self.dataForTableView = [photosRC fetchedObjects];

Hope this helps,
Wayne

Luneo

unread,
Mar 6, 2010, 2:12:30 AM3/6/10
to iPhone Application Development Auditors
I can't figure out why but sometimes the code [thePhoto name] didn't
work, I used [thePhoto valueForKey:@"name"].

Wayne

unread,
Mar 6, 2010, 6:20:45 AM3/6/10
to iPhone Application Development Auditors
That should be

thePhoto.name

since name is an attribute of thePhoto object. I don't know enough
about Cocoa to answer why
[thePhoto name] worked sometimes.

No idea why the [thePhoto name] works sometimes but am curious if
someone has an answer....

Wayne

Bill

unread,
Mar 6, 2010, 5:22:51 PM3/6/10
to iPhone Application Development Auditors
I'm not positive, but I think that thePhoto.name is the Objective-C
2.0 version (called dot notation) for calling thePhoto's getter
method. The previous way to do that was to use [thePhoto name].
Theoretically, they both should work the same way.

Bill

Jazmin

unread,
Mar 6, 2010, 6:27:11 PM3/6/10
to iPhone Application Development Auditors
Hi Lenny,
almost there!! I think. So I created the one-to-many relationship.
Person -->one-to-many ---> Photo
Now, how do you load the data:
1) If I load Photos first, then "person" attribute is not created yet
in the database.
2) If I load Person I need to make sure I do not duplicate, for
example "Josh" is twice in FakeData.sql.
Checking if previous value of "user" is the same, does not seem right.
We don't know if the xml is in order. I guess we can asume that in
this case. Is there a better way to do it.

Does it sound like what you did?

Thanks!!!!

Lenny Teng

unread,
Mar 6, 2010, 9:38:20 PM3/6/10
to iphone-appd...@googlegroups.com
Jazmin - I went with approach #2. I created a dictionary and basically checked if the person key existed.  That's a good question, though.  I'd be curious how other people did this.


From: Jazmin <jazm...@yahoo.com>
To: iPhone Application Development Auditors <iphone-appd...@googlegroups.com>
Sent: Sat, March 6, 2010 6:27:11 PM
Subject: [iPhone-AppDev-Auditors] Re: Another Paparazzi 2 Question
--
You received this message because you are subscribed to the Google Groups "iPhone Application Development Auditors" group.
To post to this group, send email to iphone-appd...@googlegroups.com.
To unsubscribe from this group, send email to iphone-appdev-auditors+unsub...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/iphone-appdev-auditors?hl=en.

Luneo

unread,
Mar 7, 2010, 2:09:03 AM3/7/10
to iPhone Application Development Auditors
Hi,

I checked while reading plist file that I didn't already have the user
related to a photo. I thought it would be better for me to have my
database correct.

On 7 mar, 03:38, Lenny Teng <lenny_t...@yahoo.com> wrote:
> Jazmin - I went with approach #2. I created a dictionary and basically checked if the person key existed.  That's a good question, though.  I'd be curious how other people did this.
>
> ________________________________

> From: Jazmin <jazmi...@yahoo.com>


> To: iPhone Application Development Auditors <iphone-appd...@googlegroups.com>
> Sent: Sat, March 6, 2010 6:27:11 PM
> Subject: [iPhone-AppDev-Auditors] Re: Another Paparazzi 2 Question
>
> Hi Lenny,
> almost there!! I think. So I created the one-to-many relationship.
> Person -->one-to-many ---> Photo
> Now, how do you load the data:
> 1) If I load Photos first, then "person" attribute is not created yet
> in the database.
> 2) If I load Person I need to make sure I do not duplicate, for
> example "Josh" is twice in FakeData.sql.
> Checking if previous value of "user" is the same, does not seem right.
> We don't know if the xml is in order. I guess we can asume that in
> this case. Is there a better way to do it.
>
> Does it sound like what you did?
>
> Thanks!!!!
>
> --
> You received this message because you are subscribed to the Google Groups "iPhone Application Development Auditors" group.
> To post to this group, send email to iphone-appd...@googlegroups.com.

> To unsubscribe from this group, send email to iphone-appdev-aud...@googlegroups.com.

Jazmin

unread,
Mar 7, 2010, 11:19:34 AM3/7/10
to iPhone Application Development Auditors
I give up trying to populate my coredata in a better way. I could not
figure out how to do a simple "update" on a Person,\ to add all the
pictures after it was already saved. I could not figure out how to
retrieve the Person to update it with the Picture set. Did it all at
once with weird logic. If anyone can please check this out and let me
know any comments I'd appreciated. Thank you!
FlickrFetcher *myFetcher = [FlickrFetcher sharedInstance];
NSManagedObjectContext *myObContext =[myFetcher
managedObjectContext];

Person *person = [[Person alloc]init];
Photo *photo;
NSString *myPrevName = [NSString string];
NSError *error;
if ([myFetcher databaseExists]) {
//Load data
NSMutableSet *photoSet = [NSMutableSet setWithCapacity:5];
for (NSDictionary *item in dic) {

NSLog(@"user %@",[item valueForKey:@"user"]);

//if same as previous dont change it
if ([[item valueForKey:@"user"] isEqualToString: myPrevName ] )
{
NSLog(@"same don't init person, use the same");
} else {
person = (Person *)[NSEntityDescription
insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:myObContext];
[person setName:[item valueForKey:@"user"]];
myPrevName = [item valueForKey:@"user"];

[photoSet removeAllObjects];

}

photo = (Photo *)[NSEntityDescription
insertNewObjectForEntityForName:@"Photo"
inManagedObjectContext:myObContext];

NSLog(@"path %@",[item valueForKey:@"path"]);
[photo setPath:[item valueForKey:@"path"]];
[photo setDesc:[item valueForKey:@"name"]];
[photo setBelongsTo:person];
[photoSet addObject: photo];

if (person)
[person setPhotos:photoSet];

if (![myObContext save:&error]) {
NSLog(@"Unresolved error %@", error);
}

}


Lenny Teng

unread,
Mar 7, 2010, 4:20:48 PM3/7/10
to iphone-appd...@googlegroups.com
Jazmin - Rather than creating an NSMutableSet, take a look at mutableSetValueForKey:addObject method.


From: Jazmin <jazm...@yahoo.com>

To: iPhone Application Development Auditors <iphone-appd...@googlegroups.com>
Sent: Sun, March 7, 2010 11:19:34 AM

Subject: [iPhone-AppDev-Auditors] Re: Another Paparazzi 2 Question
--
You received this message because you are subscribed to the Google Groups "iPhone Application Development Auditors" group.
To post to this group, send email to iphone-appd...@googlegroups.com.
To unsubscribe from this group, send email to iphone-appdev-auditors+unsub...@googlegroups.com.

wgp...@gmail.com

unread,
Mar 7, 2010, 5:51:35 PM3/7/10
to iPhone Application Development Auditors
Hi Marcio ... you ever get an answer to this? I'm getting the same

"Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'keypath name not found in
entity <NSSQLEntity Photo id=2>'" exception using an
NSFetchedResultsController in my PhotoListViewController (whereas the
same code .. almost identical ... in PersonListViewController works
fine).

thanks -wg

redbirdo

unread,
Mar 8, 2010, 4:41:34 AM3/8/10
to iPhone Application Development Auditors
Jasmin

Did you write your Person/Photo classes yourself, or did you generate
them from the entities in the data model? I did the latter and it
added these methods to the Person class for me:

- (void)addPhotosObject:(Photo *)value;
- (void)removePhotosObject:(Photo *)value;
- (void)addPhotos:(NSSet *)value;
- (void)removePhotos:(NSSet *)value;

This means that in order to set up the database:

for each item in plist file
1) create instance of Photo in MOC and set its path & name
2) check if there is already an instance of the required Person
(could use a temporary NSMutableDictionary or fetch from MOC)
3) if not: create instance of Person in MOC and set its name
4) *** to relate photo to person call:
[person addPhotosObject:photo];

Does that make sense?

Vicki

Bill

unread,
Mar 8, 2010, 11:09:13 AM3/8/10
to iPhone Application Development Auditors
[person addPhotosObject:photo];

Can I ask how you knew to add this line? I missed something in the
lecture or slides, because I thought that Core Data was creating the
relationship based on the xcdatamodel we created. This one line of
code turned out to be the key that was missing in my post from another
thread!

Thanks so much, Vicki! :-)

--Bill

marcio

unread,
Mar 9, 2010, 4:31:01 PM3/9/10
to iPhone Application Development Auditors
wgpubs

I was blind to the fact that NSFetchedResultsController method uses a
Sort Descriptor @"name" which assumes you named your photo's name
atttribute 'name'. Which I didnt, i had called it 'photoName'. So
all you have to do is change @"name" to @"whateveryoucalledyours" and
be done with it.

Guys, dont yall think itd be better to post code to github.com where
the code is color-coded for easier modification? Im not saying post
the complete code. I understand the Stanford Moral and Ethics Code
has to be respected but since we do post code snippets here, why not
post them at github which would make it easier to read?

I personally think once Paparazzi 3 Deadline comes around, we should
post the completed codes for Paparazzi 2 in a place like that so we
can view the different options scatter all over this group. The
reason is that i think we are here mostly to learn for our own sake
(not for a grade) and once the deadline is past for those who are in
here for a grade, we could very well help ourselves through this web
of code weve managed to create :)

Wayne

unread,
Mar 9, 2010, 4:31:16 PM3/9/10
to iPhone Application Development Auditors

Lets look at this error:

'keypath name not found in entity <NSSQLEntity Photo id=2>'

I personally feel a better work for keypath here is attribute, so to
simplify:
attribute "name" not found in entity Photo

i.e. Your photo class does not have a name attribute.

You can fix this in two ways, one is to update your Photo model the
other is to write a duplicate method in FlickrFetcher
for the method
- (NSFetchedResultsController *)fetchedResultsControllerForEntity:
(NSString*)entityName withPredicate:(NSPredicate*)predicate {
NSFetchedResultsController *fetchedResultsController;

Where you update the following line to reflect the key that you do
have for Photo
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
initWithKey:@"name" ascending:YES];

Note, I have modified my above line already with the ascending order
to get the names alphabetical for the extra credit.

If you feel like you may want to take a chainsaw to core data, you
aren't alone :-)

Hope this helps,
Wayne

Reply all
Reply to author
Forward
0 new messages