下载地址:https://github.com/halostatue/coredata-easyfetch
Core Data Easy Fetch Category
This is an Objective-C category for Core Data (NSManagedObjectContext (EasyFetch)
) that offers a few useful functions added that simplify Core Data programming for Mac OS X and iPhone OS. It's based loosely on codeby Matt Gallagher, but with several enhancements and modifications that I needed for a project I was writing that used Core Data.
License
This category is released under the MIT license.
Copyright © 2009, 2010 Austin Ziegler
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Using NSManagedObjectContext (EasyFetch)
-
Add the files to your Xcode project:
NSManagedObjectContext-EasyFetch.h NSManagedObjectContext-EasyFetch.m
-
Import the header in an implementation file that uses Core Data where you need the functionality:
#import "NSManagedObjectContext-EasyFetch.h"
-
Call one of the category methods:
[[self managedObjectContext] fetchObjectsForEntityName:@"Employee" predicateWithFormat:@"(lastName LIKE[c] 'Worsley') AND (salary > %@)", minimumSalary];
Methods inNSManagedObjectContext (EasyFetch)
There are several methods added in the EasyFetch
category, but they're all variations on two basic options for a query, which simplifies understanding them.
- Should the objects returned be filtered?
- Should the objects returned be sorted?
Accordingly, there are four categories of methods:
- All objects, unsorted
- All objects, sorted
- Some objects, unsorted
- Some objects, sorted
All methods return an NSArray
of objects returned by the query. Any exceptions thrown are unhandled by the category.
All objects, unsorted
- (NSArray*)fetchObjectsForEntityName:(NSString*)entityName;
Returns all objects from an entity in Core Data's natural (unsorted) order. Use only when you don't care about the order in which objects are processed.
All objects, sorted
- (NSArray*)fetchObjectsForEntityName:(NSString*)entityName
sortWith:(NSArray*)sortDescriptors;
Returns all objects from an entity, sorted by the NSArray
containing NSSortDescriptor
objects.
- (NSArray*)fetchObjectsForEntityName:(NSString*)entityName
sortByKey:(NSString*)key
ascending:(BOOL)ascending;
Returns all objects from an entity, sorted by the key value (which must be an attribute in the entity). Creates anNSSortDescriptor
object based on the key
and ascending
values.
Some objects, unsorted
- (NSArray*)fetchObjectsForEntityName:(NSString*)entityName
withPredicate:(NSPredicate*)predicate;
Returns the objects in an entity that match the predicate comparison rules in natural order. Use this version and construct your NSPredicate
value appropriately for predicate parameters that contain user input.
- (NSArray*)fetchObjectsForEntityName:(NSString*)entityName
predicateWithFormat:(NSString*)predicateFormat, ...;
Returns the objects in an entity that match the constructed predicate, in natural order. An NSPredicate
will be created using [NSPredicate predicateWithFormat:arguments:]
. Fast and easy, but unsafe for values that involve user input.
Some objects, sorted
- (NSArray*)fetchObjectsForEntityName:(NSString*)entityName
sortWith:(NSArray*)sortDescriptors
withPredicate:(NSPredicate*)predicate;
Returns the objects in an entity that match the predicate comparison rules, sorted by the NSArray
containingNSSortDescriptor
objects. Use this version and construct your NSPredicate
value appropriately for predicate parameters that contain user input.
- (NSArray*)fetchObjectsForEntityName:(NSString*)entityName
sortByKey:(NSString*)key
ascending:(BOOL)ascending
withPredicate:(NSPredicate*)predicate;
Returns the objects in an entity that match the constructed predicate, sorted by the key value (which must be an attribute in the entity). Creates an NSSortDescriptor
object based on the key
and ascending
values. Use this version and construct your NSPredicate
value appropriately for predicate parameters that contain user input.
- (NSArray*)fetchObjectsForEntityName:(NSString*)entityName
sortWith:(NSArray*)sortDescriptors
predicateWithFormat:(NSString*)predicateFormat, ...;
Returns the objects in an entity that match the predicate comparison rules, sorted by the NSArray
containingNSSortDescriptor
objects. An NSPredicate
will be created using[NSPredicate predicateWithFormat:arguments:]
. Fast and easy, but unsafe for values that involve user input.
- (NSArray*)fetchObjectsForEntityName:(NSString*)entityName
sortByKey:(NSString*)key
ascending:(BOOL)ascending
predicateWithFormat:(NSString*)predicateFormat, ...;
Returns the objects in an entity that match the constructed predicate, sorted by the key value (which must be an attribute in the entity). Creates an NSSortDescriptor
object based on the key
and ascending
values. An NSPredicate
will be created using [NSPredicate predicateWithFormat:arguments:]
. Fast and easy, but unsafe for values that involve user input.
Background & Design Notes
As stated at the beginning, this is loosely based on code by Matt Gallagher, where he writes:
It's a lot easier to get your data out of Core Data than the documentation will tell you. This simple 1-line fetch will work just as well as Apple's suggested 10-line approach for most uses.
He points out that the Core Data Programming Guide gives a multi-line approach to fetching data from a Core Data entity:
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Employee"
inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
// Set example predicate and sort orderings...
NSNumber *minimumSalary = ...;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(lastName LIKE[c] 'Worsley') AND (salary > %@)",
minimumSalary];
[request setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"firstName" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (array == nil)
{
// Deal with error...
}
Matt's sample code simplifies the above fetch to a single line:
[[self managedObjectContext] fetchObjectsForEntityName:@"Employee"
withPredicate:@"(lastName LIKE[c] 'Worsley') AND (salary > %@)",
minimumSalary];
When I found this, it simplified my Core Data code significantly, but it turned out to be insufficient for my purposes. Not only did I need filtering, I needed sorting; I also had a couple of small cases where I just needed everything (the equivalent of SELECT * FROM Employee
in SQL).
Matt mentioned that his pattern of using id
as the type of the withPredicate:
parameter was questionable design. Because it was id
, he could do some checking inside fetchObjectsForEntityName:withPredicate:
to determine whether the parameter was an NSPredicate
or an NSString
to be converted into anNSPredicate
with predicateWithFormat:arguments:
. I've written similar code in Ruby, but it didn't feel right for Objective-C. It also made the string-formatted predicate too attractive for cases where your query parameters might have been based on user input.
By time I was done adding the features I needed, I had changed this design to be an explicit choice among multiple methods. Now, the resulting category offers an explicit NSPredicate
form (e.g.,fetchObjectsForEntityName:withPredicate
) and a NSString
-formatted form (e.g.,fetchObjectsForEntityName:predicateWithFormat
). It is easier to use the predicateWithFormat
methods, but it is safer to use the withPredicate
methods.
Finally, Matt's code returned NSSet
, but this turned out to be a problem for my data, so I am returningNSArray
instead; it's trivial to add [NSSet setWithArray:results]
at the end to convert the returned data to a set if you require an NSSet
instead of an NSArray
.