【发布时间】:2014-06-24 04:44:34
【问题描述】:
我想重写我在应用中创建的视图以改进布局。最初我实现了一个使用 CoreData 作为其源的 TableViewController。这个视图对我来说效果很好,直到我需要在 TableViewController 中添加更多视图,这些视图将独立于表格并且在添加更多行时不会滚动到屏幕外。根据苹果对 NSFetchedResultsController 的指南,初步实现如下:
CoreDataTableViewController.h:
@interface CoreDataTableViewController : UITableViewController <NSFetchedResultsControllerDelegate>
@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
- (void)performFetch;
@property (nonatomic) BOOL suspendAutomaticTrackingOfChangesInManagedObjectContext;
@property BOOL debug;
@end
CoreDataTableViewController.m:
@interface CoreDataTableViewController()
@property (nonatomic) BOOL beganUpdates;
@end
@implementation CoreDataTableViewController
#pragma mark - Properties
@synthesize fetchedResultsController = _fetchedResultsController;
@synthesize suspendAutomaticTrackingOfChangesInManagedObjectContext = _suspendAutomaticTrackingOfChangesInManagedObjectContext;
@synthesize debug = _debug;
@synthesize beganUpdates = _beganUpdates;
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#pragma mark - Fetching
- (void)performFetch
{
<snipped>
}
- (void)setFetchedResultsController:(NSFetchedResultsController *)newfrc
{
<snipped>
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return [self.fetchedResultsController sectionIndexTitles];
}
#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
<..snipped..>
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type
{
<...snipped...>
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext)
{
switch(type)
{
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
}
- (void)endSuspensionOfUpdatesDueToContextChanges
{
}
- (void)setSuspendAutomaticTrackingOfChangesInManagedObjectContext:(BOOL)suspend
{
}
@end
在名为 CDTVC.h 的 TableViewController 中,我创建了一个继承 来自 CoreDataTableViewController:
@interface CDTVC : CoreDataTableViewController
@property (nonatomic, copy) NSString *status;
@property (nonatomic, copy) NSString *totalTally;
@property (nonatomic, retain) IBOutlet UILabel *tallyDisplayLabel;
@end
在我的 CDTVC.m 中:
// Gets called when the managedObjectContext is ready
-(void) loadTally
{
if (managedObjectContext) {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Entry"];
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"dateCreated" ascending:NO]];
request.predicate = nil;
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
} else {
self.fetchedResultsController = nil;
}
[self performFetch]; // <<----This refreshes the tableview controller
}
根据指南,我需要自己实施,因为它不是由 家长:
#pragma mark - CoreDataViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"entryCRVPCell"];
if (cell == nil) {
UITableViewCellStyle cellStyle = UITableViewCellStyleSubtitle;
cell = [[UITableViewCell alloc] initWithStyle:cellStyle reuseIdentifier:@"entryCRVPCell"];
}
TallyEntry *tallyEntry = [self.fetchedResultsController objectAtIndexPath:indexPath];
if (tallyEntry) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"MMM dd, yyyy"];
NSString *stringDate = [dateFormatter stringFromDate:tallyEntry.dateCreated];
cell.textLabel.numberOfLines = 0;
cell.textLabel.text = [NSString stringWithFormat:@"%@ - %@\n%@", tallyEntry.category, tallyEntry.name, stringDate];
}
return cell;
}
所以现在我的视图控制器不再是 TableViewController,而是一个包含 TableView 的 ViewController:
所以我引入了一个新的视图控制器,这就是我觉得我所做的是 一个 hack,并不像解决方案那样优雅:
在 CDTVC.h 中,我添加了以下内容,以便可以访问 TallyViewController:
@protocol TallyViewDataSource
-(void)setupTallyLabel:(float) tally;
-(NSString *) getTallyMode;
@end
@property (nonatomic, retain) IBOutlet id <TallyViewDataSource> dataSource;
在 CDTVC.m 中,我添加了以下内容:
@synthesize dataSource = _dataSource;
我将 loadTally 实现移至 TallyViewController。
TallyViewController.h 现在必须从 UIViewController 继承,这意味着我 不能再从 CoreDataViewController 继承:
@interface TallyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate,
TallyViewDataSource> {
IBOutlet UITableView* myTableView;
}
@property (nonatomic, retain) IBOutlet UILabel *tallyDisplayLabel;
@property (nonatomic, retain) IBOutlet UITableView *myTableView;
@property (nonatomic, retain) CDTVC* CDTVCTable;
所以为了解决这个多重继承问题,我决定分配我的 在我的 TallyViewController.m 中拥有自己的 CDTVCTable 实例:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_CDTVCTable = [[CDTVC alloc] init];
_CDTVCTable.dataSource = self;
}
-(void) loadTally
{
if (managedObjectContext) {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Entry"];
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"dateCreated" ascending:NO]];
request.predicate = nil;
_CDTVCTable.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
} else {
_CDTVCTable.fetchedResultsController = nil;
}
[_CDTVCTable performFetch];
[self.myTableView reload]; //<----Had to add this to refresh the local table.
}
我还必须实现所有的表视图委托,但将它们重定向到 我的 CDTVCTable,和以前一样,我只需要实现 tableView: cellForRowAtIndexPath:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [_CDTVCTable numberOfSectionsInTableView:tableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [_CDTVCTable tableView:tableView numberOfRowsInSection:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [_CDTVCTable tableView:tableView cellForRowAtIndexPath:indexPath];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
return [_CDTVCTable tableView:tableView commitEditingStyle:editingStyle forRowAtIndexPath:indexPath];
}
所以问题是,有没有更优雅的方法来实现它 代表和数据源。我不得不承认我对代表和 数据源很弱,所以我不确定以更好的方式概述这一点。
【问题讨论】:
-
要消化的东西太多了。如果您能更简洁地陈述您的问题,您将更有可能获得体面的答案。
-
我想给出一个完整的图片以避免单线答案:使用代表,我不清楚如果这是采取的方法。
标签: ios objective-c uitableview core-data uiviewcontroller