Friday, August 7, 2015

iOS Tutorial - Part 33 - Core Data II

Core Data II


Video Description 
In previous session we learnt how to add items inside of database, in this tutorial we will learn how to search through the database and also the proper way of adding items inside of database.

Proper way of adding items in database

Previous tutorial showed the easiest way of adding items inside of database but here is the best practice of adding data into database:
+ (Students *)addStudentInfoFromDictionary:(NSDictionary *)studentInfo
{
    AppDelegate *appDelegate= (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    
    Students *studentEntity = nil;
    
    NSString *studentId = studentInfo[@"studentId"];
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Students"];
    request.predicate = [NSPredicate predicateWithFormat:@"studentId = %@", studentId];
    
    NSError *error;
    NSArray *matches = [context executeFetchRequest:request error:&error];
    
    
    if (!matches || error || ([matches count] > 1))
    {
        //Handle Errors
    }
    else if ([matches count])
    {
        //Returns the existing object
        studentEntity = [matches firstObject];
    }
    else
    {
        //Create a new Object
        studentEntity = [NSEntityDescription insertNewObjectForEntityForName:@"Students" inManagedObjectContext:context];
        studentEntity.studentId = [studentInfo valueForKey:@"studentId"];
        studentEntity.name  = [studentInfo valueForKey:@"name"];
        studentEntity.lastName = [studentInfo valueForKey:@"lastName"];
        
        NSError *error;
        if (![context save:&error]) {
            NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
        }
    }
    return studentEntity;
}
First we check for a unique identifier in order to avoid duplicating data. In this example studentId is our unique identifier. We request a fetch through the database via NSFetchRequest. It needs the entity name in order to be initialized. Our entity name is "Students" so we add Students as entity name. Then we define a predicate. Predicate is for defining our query for search. The following line means, give me all the data that has studentId that is equal to the one that is passed to this function.
[NSPredicate predicateWithFormat:@"studentId = %@", studentId];
Since during fetch request we may get some errors, we define NSError. Then we execute the fetch request and assign the result to an array because it returns all matched results as an array. Now we have to check the matches. If matches null or it's more than one item or error is not null, we know that we have error and this if statement is for handling errors. matches should not be more than one because studentId is unique and we should have only one instance of that ID.
If matches not null and equals one, it goes to the second statement. If it goes to this statement it shows that we had this item already in the database so we just return the mach that we found.
If non of the above statements get valid, we know that it's totally new item and we add it to the database. The implementations is exactly like the one that we had in previous session.

Query the database (Search through Core Data)

Suppose that we want to search the database to find all the matches for a specific name or specific lastname. The following method can search the database to find all matches for the name and lastname that you specify. It uses the same NSFetchRequest format that we used above. Also the same NSPredicate but with different format. This time we want to check for name, so it searches for name. If we want to search the name and lastname, we put AND in our format. There are other things that we can use in our format like OR. Based on your needs you can find the proper format and pass it into the predicateWithFormat. The second function is a helper function to create a temporary dictionary for each result.
+ (NSArray *)searchStudensByName:(NSString *)name lastname:(NSString *)lastname
{
    AppDelegate *appDelegate= (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    
    NSError *error;
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Students"];
    request.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND lastName == %@", name, lastname];
    
    NSArray *fetchedObject = [context executeFetchRequest:request error:&error];
    NSMutableArray *results = [[NSMutableArray alloc] init];
    
    for (Students *studentEntity in fetchedObject)
    {
        [results addObject:[self createObjectFromEntity:studentEntity]];
    }
    return results;
}

+(NSDictionary *)createObjectFromEntity:(Students *)studentInfo
{
    NSMutableDictionary *tempDict = [[NSMutableDictionary alloc] init];
    tempDict[@"name"] = studentInfo.name;
    tempDict[@"lastName"] = studentInfo.lastName;
    tempDict[@"studentId"] = studentInfo.studentId;
    return tempDict;
}

Download

Download this App from HERE.