2
\$\begingroup\$

I am fetching or querying all the entries from my database (core-data) at three different times in my code, which I find to be an inefficient approach to writing the code.

The method _walks = [[DatabaseManager sharedDatabaseManager] getAllWalks]; helps getting all the entries from the database in the form of NSArray.

I call _walks = [[DatabaseManager sharedDatabaseManager] getAllWalks]; for the first time in the viewDidLoad method, so that I can get all the entries when I launch my app.

Next, I call _walks = [[DatabaseManager sharedDatabaseManager] getAllWalks]; when I click on the add button, which invokes the (IBAction)addAction:(id)sender method, so that my entry gets updated in the TableViewCells.

Lastly, I call _walks = [[DatabaseManager sharedDatabaseManager] getAllWalks]; in the (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section method, in order to update the row count, so that the row count remains inline with the entries in database event after I delete my entries.

Please let me know how I can avoid fetching all the entries three times. Also let me know if I have not followed good practice in this code.

Project

#import "ViewController.h"
#import "DatabaseManager.h"
#import "Walks.h"

@interface ViewController ()

@property (strong,nonatomic) NSArray *walks;
@property (weak, nonatomic) IBOutlet UITableView *tableView;

@end

@implementation ViewController
@synthesize tableView = _tableView;
@synthesize walks = _walks;

-(void)viewDidAppear:(BOOL)animated{
    [[DatabaseManager sharedDatabaseManager] simpleAddaDog];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
    _walks = [[DatabaseManager sharedDatabaseManager] getAllWalks];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}
- (IBAction)addAction:(id)sender {
    [[DatabaseManager sharedDatabaseManager]addWalk:[NSDate date]];
    _walks = [[DatabaseManager sharedDatabaseManager] getAllWalks];
    [self.tableView reloadData];
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    _walks = [[DatabaseManager sharedDatabaseManager]getAllWalks];
    return _walks.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"Cell";
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
    if(cell == nil){
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }

    NSString *dateString = [NSDateFormatter localizedStringFromDate:[_walks[indexPath.row] date]
                                                          dateStyle:NSDateFormatterShortStyle
                                                          timeStyle:NSDateFormatterShortStyle];
    NSLog(@"dateString = %@",dateString);
    cell.textLabel.text = dateString;
    return cell;
}

-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
    return TRUE;
}

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
    [_tableView beginUpdates];
    if(editingStyle == UITableViewCellEditingStyleDelete){
        Walks *walkToRemove = _walks[indexPath.row];
        [[DatabaseManager sharedDatabaseManager]deleteTheWalks:walkToRemove];
        [_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

    [_tableView endUpdates];
    }
}


@end

Core-data stack:

//
//  DatabaseManager.m
//  DogWalk
//
//  Created by Nilesh Agrawal on 11/9/14.
//  Copyright (c) 2014 Nilesh Agrawal. All rights reserved.
//

#import "DatabaseManager.h"
#import "Dog.h"
#import "MyConstants.h"


static DatabaseManager *_sharedInstance;
@implementation DatabaseManager
@synthesize persistantStore =_persistantStore;
@synthesize managedContext = _managedContext;
@synthesize managedObject =_managedObject;
@synthesize managedObjectModel =_managedObjectModel;


+(DatabaseManager *)sharedDatabaseManager{
    @synchronized(self){
        if(_sharedInstance==nil){
            _sharedInstance = [[DatabaseManager alloc] init];
        }
    }
    return _sharedInstance;
}

-(id)init{
    if(self = [super init]){

    }
    return self;
}

-(NSURL *)applicationDocumentsDirectory{

    /*
        to get the location of the persistant store.
     */

    return [[[NSFileManager defaultManager]URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]lastObject];

}

-(NSManagedObjectModel *)managedObjectModel{

    //checkif the managedObjectModel is null otherwise create a new one.
    if(_managedObjectModel !=nil){
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle]URLForResource:@"DogWalk" withExtension:@"momd"];

    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

-(NSPersistentStoreCoordinator*)persistantStoreCoordinator{
    //first check if the persistant store is nil or not, if not nill then return that one.
    NSPersistentStoreCoordinator *persistantStoreCoordinator=nil;

    //if the persistant store is nill, then create a new one.
    //Adding the managedObejct Model to the persistant store.
    persistantStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"DogWalk.sqlite"];
    NSError *err=nil;
    //Adding the store to the persistant store co-ordinator.
    if(![persistantStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&err]){
        //in case if error occurs.
        NSLog(@"Error,=%@ErrorInfo= %@",err.description,err.userInfo);
    }
    return persistantStoreCoordinator;
}


-(NSManagedObjectContext *)managedObjectContext{
    if(_managedContext!=nil){
        return _managedContext;
    }
    NSPersistentStoreCoordinator *persistantStoreCoordinator = [self persistantStoreCoordinator];
    if(persistantStoreCoordinator==nil){
        return nil;
    }
    _managedContext = [[NSManagedObjectContext alloc]init];
    [_managedContext setPersistentStoreCoordinator:persistantStoreCoordinator];
    return _managedContext;
}

-(void)simpleAddaDog{
    NSManagedObjectContext *context = [self managedObjectContext];
    NSString *dogName = @"Tommy";
    Dog *dog =[NSEntityDescription insertNewObjectForEntityForName:@"Dog" inManagedObjectContext:context];
    dog.name = dogName;
    [context save:nil];
}

-(void)addWalk:(NSDate *)date{
    NSManagedObjectContext *context = [self managedObjectContext];
    NSFetchRequest *fetchedRequest = [[NSFetchRequest alloc] init];
    /*
     fetch the first dog and then add walks to it .
     */
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Dog" inManagedObjectContext:context];
    [fetchedRequest setEntity:entity];
    NSArray *fetchedObjects = [context executeFetchRequest:fetchedRequest error:nil];
    Dog *dog = fetchedObjects[0];
    Walks *walk = [NSEntityDescription insertNewObjectForEntityForName:@"Walks" inManagedObjectContext:context];
    walk.date = date;
    NSMutableOrderedSet *walks = [dog.walks mutableCopy];
    [walks addObject:walk];
    dog.walks = walks.copy;
    [context save:nil];
}


-(NSArray *)getAllWalks{
    NSManagedObjectContext *context = [self managedObjectContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Dog" inManagedObjectContext:context];
    [fetchRequest setEntity:entityDescription];
    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:nil];
    if((long)fetchedObjects.count < 0){
        return nil;
    }
    NSArray *dogArray = [[NSArray alloc] init];
    if((long)fetchedObjects.count>0){
        Dog *dog = fetchedObjects[0];
        NSFetchRequest *fetchRequestDog = [[NSFetchRequest alloc] init];
        NSEntityDescription *entityDescriptionDog = [NSEntityDescription entityForName:@"Walks" inManagedObjectContext:context];
        [fetchRequestDog setEntity:entityDescriptionDog];
        fetchRequestDog.predicate = [NSPredicate predicateWithFormat:@"dog==%@",dog];
        dogArray = [context executeFetchRequest:fetchRequestDog error:nil];
        NSLog(@"dog name = %@, dog Array Count = %ld",dog.name, dogArray.count);
    }
    return dogArray;
}

-(void)deleteTheWalks:(Walks *)WalkToRemove{
    NSManagedObjectContext *managedContext =[self managedContext];
    [managedContext deleteObject:WalkToRemove];
    [managedContext save:nil];
}
@end
\$\endgroup\$
3
\$\begingroup\$

First of all, take _walks as NSMutableArray so when you add new walks, you can directly add to the array and reload the table.

@property (strong,nonatomic) NSMutableArray *walks;

In viewDidLoad, fetch the array only once.

_walks = [[NSMutableArray alloc]initWithArray:[[DatabaseManager sharedDatabaseManager] getAllWalks]];

Your IBAction method should look like the one below. Your database manager will return a walks object which you are directly adding to the array, so no need to fetch data from the database.

- (IBAction)addAction:(id)sender {
    [_walks addObject:[[DatabaseManager sharedDatabaseManager]addWalk:[NSDate date]]];
    //_walks = [[DatabaseManager sharedDatabaseManager] getAllWalks];
    [self.tableView reloadData];
}

No need to fetch data in numberOfRowsInSection:; simply return your array count:

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return _walks.count;
}

In DatabaseManager.m, when saving context, return the same object after adding:

-(Walks *)addWalk:(NSDate *)date{
    NSManagedObjectContext *context = [self managedObjectContext];
    NSFetchRequest *fetchedRequest = [[NSFetchRequest alloc] init];
    /*
     fetch the first dog and then add walks to it .
     */
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Dog" inManagedObjectContext:context];
    [fetchedRequest setEntity:entity];
    NSArray *fetchedObjects = [context executeFetchRequest:fetchedRequest error:nil];
    Dog *dog = fetchedObjects[0];
    Walks *walk = [NSEntityDescription insertNewObjectForEntityForName:@"Walks" inManagedObjectContext:context];
    walk.date = date;
    NSMutableOrderedSet *walks = [dog.walks mutableCopy];
    [walks addObject:walk];
    dog.walks = walks.copy;
    [context save:nil];
    return walk;
}

Now a walks object will be added to your array. Now just reload the table.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.