开发者

Walking Core Data graph to-many relationships always seems awkward, is there a better way?

I'm able to get things working fine with Core Data and to achieve my desired result开发者_开发技巧s, but I always feel it very awkward when walking to-many relationships because NSSet is, for my typical purposes, fairly useless.

An example is if I have obtained a NSManagedObject of Entity "Zoo" with attribute "nameOfZoo" and to-many relationship "animalCages", the to-many relationship pointing to Entity "AnimalCage" which has attribute "nameOfSpecies" and to-many relationship pointing to Entity "IndividualAnimal"

Zoo [nameOfZoo] ->> AnimalCage [nameOfSpecies] ->> Animals

So, getting the top level Zoo object, that's simple. But then I want to get the data for nameOfSpecies "Canus Lupus". The code I want to write is this:


// Normal NSEntityRequest or whichever it is, I have no gripe with this
NSManagedObject *zoo = ..the request to get the one Zoo..;

// I want to get the object where the key "nameOfSpecies" is set to "CanusLupus" NSManagedObject *wolf = [[zoo animalCages] object:@"Canus Lupus" forKey:@"nameOfSpecies"];

Obviously, I can't obtain wolf in this manner. Instead, I have to write like 10 lines of code (feels like 100 lines of code) to first obtain the set, then set up a search predicate request, and declare an error variable, execute the request, then get an array of the results, then get the first element of that array.. and if I want to walk further down the tree, to find the animal named "Wolfy" for instance, then I have to do it all over again.

Am I doing things correctly or am I foolishly an easier way? I guess I can put a category on NSSet, maybe I will, but I feel like there should be a built in better way. If not, why?


If you have a data model like this:

Zoo{
  name:string
  animalCages<-->>AnimalCage.zoo
}

AnimalCage{
  nameOfSpecies:string
  zoo<<-->Zoo.animalCages
  animals<-->>Animal.animalCage
}

Animal{
  name:string
  animalCage<<-->AnimalCage.animals
}

The to find a specific AnimalCage by name of species for a given Zoo object:

  NSString *soughtSpecies=@"Canis Lupis"; // normally this variable would be passed in to the method
  NSPredicate *p=[NSPredicate predicateWithFormat:@"nameOfSpecies==%@", soughtSpecies];
  NSSet *wolves=[[zoo animalCages] filteredSetUsingPredicate:p];

Or you can use objectPassingTest: if you like blocks.

If you use custom NSManagedObject subclasses, then you get custom accessor methods and can use self.dot notation so the above would be:

  Zoo *zoo= // fetch the appropriate zoo object
  NSString *soughtSpecies=@"Canis Lupis";
  NSPredicate *p=[NSPredicate predicateWithFormat:@"nameOfSpecies==%@", soughtSpecies];
  NSSet *wolves=[zoo.animalCages filteredSetUsingPredicate:p];

If you know before hand that you are going to have to find cages a lot, you could wrap the above up in a method on your Zoo class e.g.

@implementation Zoo
//... other stuff
-(AnimalCage *) cageForSpecieNamed:(NSString *) specieName{
  NSPredicate *p=[NSPredicate predicateWithFormat:@"nameOfSpecies==%@", specieName];
  NSSet *wolves=[self.animalCages filteredSetUsingPredicate:p];
  return [wolves anyObject]; // assuming one cage per species
}

Objective-c is intentionally verbose because it was supposed to be "self documenting" and the editor written for the language at the beginning had autocomplete. So, if your used to a more expressive language it might seem you are doing a lot of work but logically you aren't.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜