views:

54

answers:

3

Hello, i m not sure how to describe this as i m new with all the developing and i m really looking forward to an answer from you guys. I know you can be very busy but please try to HELP me!

Here it goes. I have an app that loads a very large database (although it only has 100 entries it contains HiRes images (100MB) ).

At start up a tableview presents the rows -records (using only 3 attributes from the database). However it seems that the WHOLE database (including the images) is loaded at start up! IS THERE A WAY TO ONLY LOAD THE 3 attributes (something like "select") when the app starts and then when the user moves to didselectrowatindexpath load the rest of the record?

Because i have NO IDEA where to look or what to do i would appreciate some coding help!

here is the code i m using:

#pragma mark -
#pragma mark App support

- (NSFetchedResultsController *)resetFetchedResultsController:(NSPredicate *)predicate cached:(BOOL)cached
{

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Records" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];


    NSSortDescriptor *partDescriptor = [[NSSortDescriptor alloc] initWithKey:@"displayOrder" ascending:YES];
    NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: partDescriptor, nameDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];


    if (predicate != nil)
        [fetchRequest setPredicate:predicate];

    NSString *cacheName = nil;
    if (cached)
        cacheName = @"Root";

    NSFetchedResultsController *aFetchedResultsController = [[[NSFetchedResultsController alloc]
                                                              initWithFetchRequest:fetchRequest
                                                              managedObjectContext:managedObjectContext
                                                              sectionNameKeyPath:nil
                                                              cacheName:cacheName] autorelease];
    aFetchedResultsController.delegate = self;

    [fetchRequest release];
    [partDescriptor release];
    [nameDescriptor release];
    [sortDescriptors release];

    NSError *error = nil;
    if (![aFetchedResultsController performFetch:&error]) {
        // Handle error
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }

    return aFetchedResultsController;
}







- (void)showRecords:(Records *)records animated:(BOOL)animated {
  .
    RecordsDetailViewController *detailViewController = [[RecordsDetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
    detailViewController.records = records;

    [self.navigationController pushViewController:detailViewController animated:animated];
    [detailViewController release];
}


#pragma mark -
#pragma mark Table view methods


- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    cell.backgroundColor = [UIColor lightGrayColor];
}



- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    NSInteger count = [[fetchedResultsController sections] count];

    if (count == 0) {
        count = 1;
    }

    return count;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    NSInteger numberOfRows = 0;

    if ([[fetchedResultsController sections] count] > 0) {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
        numberOfRows = [sectionInfo numberOfObjects];
    }

    return numberOfRows;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *RecordCellIdentifier = @"RecordCellIdentifier";

    RecordTableViewCell *recordCell = (RecordTableViewCell *)[tableView dequeueReusableCellWithIdentifier:RecordCellIdentifier];
    if (recordCell == nil) {
        recordCell = [[[RecordTableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:RecordCellIdentifier] autorelease];
        recordCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

    [self configureCell:recordCell atIndexPath:indexPath];

    return recordCell;
}


- (void)configureCell:(RecordTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    // Configure the cell
    Records *records = (Records *)[fetchedResultsController objectAtIndexPath:indexPath];
    cell.records = records;
}



- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (self.searchDisplayController.isActive)
        [self.tableView reloadData];


    Records *records = (Records *)[fetchedResultsController objectAtIndexPath:indexPath];

    [self showRecords:records animated:YES];
}

//this is from the RecordTableViewCell.m to show you the attributes i m using:

#pragma mark -
#pragma mark Record set accessor

- (void)setRecord:(Record *)newRecord {
    if (newRecord != record) {
        [record release];
        record = [newRecord retain];
    }
    imageView.image = [UIImage imageNamed:@"icon.png"];
    nameLabel.text = record.name;
    overviewLabel.text = record.overview;
    partLabel.text = record.part;
}

thanks again...

A: 

I would separate the large file from the metadata, because I like to have the freedom to manage these expensive resources seParately. Then I could store them differently, eg filesystem, or http server. This allows me to cache them or send them to remote locAtions proactively to reduce the download times

The rest of the table can then fit in less blocks in the database so less disk access is needed. Many databases do this internally anyway, eg postgresql

You can the just refer to the heavy resource by Id

Peter Tillemans
so there is no way to just load certain attributes of an entity in a DB instead of loading the whole thing at start up?
treasure
A: 

Sorry for posting this as an answer, but I would like to show you the code.

So here I am trying to fetch certain attributes from an entity. This is the code I'm using but I get an error and the app crashes...

// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Records"
                                    inManagedObjectContext:managedObjectContext];

// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setReturnsDistinctResults:YES];

[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:@"displayOrder",
                                            @"name", @"overview", @"part", nil]];

// Edit the sort key as appropriate.
NSSortDescriptor *partDescriptor =
        [[NSSortDescriptor alloc] initWithKey:@"displayOrder" ascending:YES];
NSSortDescriptor *nameDescriptor =
        [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors =
        [[NSArray alloc] initWithObjects: partDescriptor, nameDescriptor, nil];

Am I missing something?

treasure
A: 

Ok here it goes. I ve gave up the idea of loading separately the attributes that i need at start up. What i ve done AND NOW WORKS FLAWLESSLY is to do create RELATIONSHIPS in my model. Images are now loading only when called!

This solution was in my mind but because i had already populated my database it was difficult for me to repeat this step.

However i m glad that i did!

NOW it works as it should!!

Happy Developer!!

treasure