首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NSFetchedResultsController实现

NSFetchedResultsController实现
EN

Code Review用户
提问于 2013-03-12 06:32:48
回答 1查看 700关注 0票数 4

我使用的是核心数据和NSFetchedResultsController。有什么可以改进的吗?

代码语言:javascript
复制
//
//  RoutineTableViewController.m
//  App
//
//  Created by Me on 3/21/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "RoutineTableViewController.h"
#import <QuartzCore/QuartzCore.h>
#import "FlurryAnalytics.h"
#import "RoutineDayTableViewController.h"
#import "Routine.h"
#import "Exercise.h"
#import "DataModelController.h"


@implementation RoutineTableViewController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:YES];
    self.fetchedResultsController = nil;
    [self.fetchedResultsController performFetch:nil];
    [self toggleEditButton];
}


- (void)viewDidLoad {
    [super viewDidLoad];

    [FlurryAnalytics logEvent:@"Routine"];

    if (!self.managedObjectContext) {
        self.managedObjectContext = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 
    }

    self.navigationItem.title = @"Routines";
    self.routineTableView.rowHeight = 65;
    self.routineTableView.delegate = self;
    self.routineTableView.backgroundColor = [UIColor clearColor];
    self.view.backgroundColor = [UIColor myBackgroundColor];

    self.navigationItem.leftBarButtonItem = self.editButtonItem;    
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(presentCreateRoutineAlert)];

    [self toggleEditButton];
}


- (void)toggleEditButton {
    if (!self.fetchedResultsController.fetchedObjects.count > 0) {
        self.navigationItem.leftBarButtonItem.enabled = NO;
    } else {
        self.navigationItem.leftBarButtonItem.enabled = YES;
    }
}


-(void)presentCreateRoutineAlert {    
    UIAlertView *anAlert = [[UIAlertView alloc]initWithTitle:@"Add Routine" message:@"Enter name for routine" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Create", nil];
    [anAlert setAlertViewStyle:UIAlertViewStylePlainTextInput];
    [anAlert show];
}


- (void)alertView:(UIAlertView *)iAlertView willDismissWithButtonIndex:(NSInteger)iButtonIndex {
    if (iButtonIndex != [iAlertView cancelButtonIndex]) {
        NSString *aRoutineName = [iAlertView textFieldAtIndex:0].text;
        [self createRoutineWithName:aRoutineName];
    }
}


-(void)createRoutineWithName:(NSString *)iRoutineName {
    Routine *aRoutine = [DataModelController createRotuineWithName:iRoutineName];
    [self.routineTableView reloadData];
    [self pushToListForRoutine:aRoutine];
}


-(void)pushToListForRoutine:(Routine *)iRoutine {
    RoutineDayTableViewController *detailViewController = [[RoutineDayTableViewController alloc] initWithNibName:@"RoutineDayTableViewController" bundle:nil withRoutine:iRoutine];
    detailViewController.hidesBottomBarWhenPushed = YES;
    [self.navigationController pushViewController:detailViewController animated:YES];
}


#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}


- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    cell.imageView.image = [UIImage imageNamed:@"44-shoebox.png"];
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"newcell.png"]];
    cell.textLabel.backgroundColor = [UIColor clearColor];
    cell.detailTextLabel.backgroundColor = [UIColor clearColor];
    cell.textLabel.font = [UIFont textLabelFontBig];

    Routine *aRoutine = (Routine *)[self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = aRoutine.name;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [self.routineTableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }

    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}


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


- (void)setEditing:(BOOL)editing animated:(BOOL)animate {
    [self.routineTableView setEditing: !self.routineTableView.editing animated:YES];

    if (self.routineTableView.editing)
        [self.navigationItem.leftBarButtonItem setTitle:@"Done"];
    else
        [self.navigationItem.leftBarButtonItem setTitle:@"Edit"];
}


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
     if (editingStyle == UITableViewCellEditingStyleDelete) {
         NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
         [context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];

         NSError *error = nil;

         if (![self.managedObjectContext save:&error]) {
             NSLog(@"error: %@", error);
         }
     }
}


- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}


#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    Routine *aRoutine = (Routine *)[self.fetchedResultsController objectAtIndexPath:indexPath];
    [self pushToListForRoutine:aRoutine];
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}


#pragma mark - Fetched results controller


- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Routine" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:YES];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    NSError *error = nil;
    if (![theFetchedResultsController performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _fetchedResultsController;
}


#pragma mark - Fetched results controller delegate


- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.routineTableView beginUpdates];
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.routineTableView endUpdates];
    [self toggleEditButton];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.routineTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
        case NSFetchedResultsChangeDelete:
            [self.routineTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    UITableView *tableView = self.routineTableView;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
    }
}


@end
EN

回答 1

Code Review用户

发布于 2013-04-20 22:23:43

简单地看一下表视图控制器代码,我通常会建议一种更有效的配置单元格的方法。你有:

代码语言:javascript
复制
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    cell.imageView.image = [UIImage imageNamed:@"44-shoebox.png"];
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"newcell.png"]];
    cell.textLabel.backgroundColor = [UIColor clearColor];
    cell.detailTextLabel.backgroundColor = [UIColor clearColor];
    cell.textLabel.font = [UIFont textLabelFontBig];

    Routine *aRoutine = (Routine *)[self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = aRoutine.name;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [self.routineTableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }

    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}

这意味着每次请求单元格时都会运行configureCell:atIndexPath:,每当用户滚动表时就会发生这种情况。这种方法中的大部分工作只需要在创建新单元时才能完成,这在每个用户滚动过程中都不一定发生(因为单元格是循环的)。

..。特别是在这个方法中创建一个新的UIImageView,这是不必要的。看起来只有这一行:

代码语言:javascript
复制
cell.textLabel.text = aRoutine.name;

每次请求单元格时都需要运行,因为名称可以更改。因此,我会将代码移出configureCell:atIndexPath:,并将您的代码更改为:

代码语言:javascript
复制
   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [self.routineTableView dequeueReusableCellWithIdentifier:CellIdentifier];

        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
            [self configureCell:cell atIndexPath:indexPath];
        }

        // update the cell label for this specific routine name:
        Routine *aRoutine = (Routine *)[self.fetchedResultsController objectAtIndexPath:indexPath];
        cell.textLabel.text = aRoutine.name;

        return cell;
    }

现在,按照我们使用configureCell:atIndexPath:的方式,将其重命名为initializeCell:atIndexPath:之类可能会更清楚。此外,如果该方法中的代码太多,我可能建议创建一个UITableViewCell的新子类,并将所有这些代码放入其initWithStyle:reuseIdentifier:方法中,这样就可以从表视图控制器中完全删除对configureCell:atIndexPath:的调用。

但是,这将是一个代码模块化/整洁的问题。我提出的关于不每次调用configureCell:atIndexPath:的第一点实际上是一个性能问题。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/23769

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档