Rob Rob - 1 year ago 74
iOS Question

How to make a conditional request with NSManagedObjectContext?

I'm new to

. I have created an entity
in my app, which contains a
NSString *url

At some point of my app, I need to insert a new
in my base, so I simply do this :

Link *link = [NSEntityDescription
link.url = myUrl;

But before doing this, I want to check if there is not already a Link in my base with the same url. And I have no idea of how to do so... what should I do?

EDIT : to retrieve data from the base I'm using this method from a tool I found on the web:

// Fetch objects with a predicate
+(NSMutableArray *)searchObjectsForEntity:(NSString*)entityName withPredicate:(NSPredicate *)predicate andSortKey:(NSString*)sortKey andSortAscending:(BOOL)sortAscending andContext:(NSManagedObjectContext *)managedObjectContext
// Create fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[request setEntity:entity];

// If a predicate was specified then use it in the request
if (predicate != nil)
[request setPredicate:predicate];

// If a sort key was passed then use it in the request
if (sortKey != nil) {
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];

// Execute the fetch request
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];

// If the returned array was nil then there was an error
if (mutableFetchResults == nil)
NSLog(@"Couldn't get objects for entity %@", entityName);

// Return the results
return mutableFetchResults;

I would like to know how to use it.

Thanks for your help.

Answer Source

The method you provided just searches for a NSManagedObject that matches the attributes in the NSManagedObjectContext and if one exists, it returns it.

But, what you need to implement is called the Find-or-Create pattern, which is discussed in the Core Data programming guide. Basically, you search for an object matching specific criteria and if it exists that object is returned. If that object does not exist you create it.

Core Data Programming Guide


+ (NSString *)entityName
    return NSStringFromClass([Link class]);

+ (instancetype)findUsingPredicate:(NSPredicate *)predicate withContext:(NSManagedObjectContext *)context
    Link * entity;

    // Setup the fetchRequest
    NSFetchRequest * fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[[self class] entityName]];
    fetchRequest.predicate = predicate;

    // Credit: @Martin R
    [fetchRequest setFetchLimit:1];

    // Execute the fetchRequest
    NSError *error = nil;
    NSArray * matchingLinks = [context executeFetchRequest:fetchRequest error:&error];

    // MatchingLinks will only return nil if an error has occurred otherwise it will return 0
    if (!matchingLinks)
        // handle error
        // Core data returns nil if an error occured
        NSLog(@"%s %@", __PRETTY_FUNCTION__, [error description]);
    else if ([matchingLinks count] <= 0)
        // if the count <= 0, there were no matches

        NSLog(@"%s Not found", __PRETTY_FUNCTION__);

    } else {

        // A link with a url that matches the url in the dictionary was found.
        NSLog(@"%s Found", __PRETTY_FUNCTION__);

        entity = [matchingLinks lastObject];

    return entity;

+ (instancetype)findUsingPredicate:(NSPredicate *)predicate orCreateWithContext:(NSManagedObjectContext *)context
    Link * entity = [[self class] findUsingPredicate:predicate withContext:context];

    if (!entity) {
        entity = [[self class] createWithContext:context];

    return entity;

+ (isntancetype)createWithContext:(NSManagedObjectContext *)context
    return [[self class] alloc] initWithContext:context];

- (instancetype)initWithContext:(NSManagedObjectContext *)context
    Link * entity = [NSEntityDescription insertNewObjectForEntityForName:[[self class] entityName] inManagedObjectContext:context];

    return entity;


NSString * url = @"";
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"url = %@", url];
Link * link = [Link findUsingPredicate:predicate orCreateWithContext:self.managedObjectContext];
link.url = url;