CoreData TableView里面的UIViewController [英] CoreData TableView inside UIViewController

查看:191
本文介绍了CoreData TableView里面的UIViewController的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想重写一个视图,我在我的应用程序,以改善布局。最初我实现了一个使用CoreData作为其源的TableViewController。这个视图对我来说很好,直到我需要在TableViewController中添加更多的视图,这些视图将作为表的独立表现,并且在添加更多的行时不会滚动到屏幕外。基于对NSFetchedResultsController的苹果指南,初始实现如下:



CoreDataTableViewController.h:

  @interface CoreDataTableViewController:UITableViewController< NSFetchedResultsControllerDelegate> 
@property(strong,nonatomic)NSFetchedResultsController * fetchedResultsController;
- (void)performFetch;
@property(nonatomic)BOOL suspendAutomaticTrackingOfChangesInManagedObjectContext;
@property BOOL调试;
@end

CoreDataTableViewController.m:


$ b b

  @interface CoreDataTableViewController()
@property(nonatomic)BOOL beginsUpdates;
@end

@implementation CoreDataTableViewController

#pragma mark - 属性

@synthesize fetchedResultsController = _fetchedResultsController;
@synthesize suspendAutomaticTrackingOfChangesInManagedObjectContext = _suspendAutomaticTrackingOfChangesInManagedObjectContext;
@synthesize debug = _debug;
@synthesize beginsUpdates = _beganUpdates;

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}

#pragma mark - 获取

- (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 section] 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 b $ b {
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
{
}
b $ b @end



在我的TableViewController中,名为CDTVC.h,我创建了一个继承$来自CoreDataTableViewController的b $ b:

  @interface CDTVC:CoreDataTableViewController 
@property(nonatomic,copy)NSString * status;
@property(nonatomic,copy)NSString * totalTally;
@property(nonatomic,retain)IBOutlet UILabel * tallyDisplayLabel;
@end

在我的CDTVC.m:

  //当managedObjectContext准备就绪时调用
- (void)loadTally
{
if(managedObjectContext){
NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@Entry];
request.sortDescriptors = @ [[NSSortDescriptor sortDescriptorWithKey:@dateCreatedascending:NO]];
request.predicate = nil;

self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
} else {
self.fetchedResultsController = nil;
}

[self performFetch]; //<< ----这刷新了tableview控制器
}

Per指南,我需要实现这个自己,因为它不是由
父母处理:

  #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:@%@ - %@ \\\
%@,tallyEntry.category,tallyEntry.name,stringDate];
}

return cell;
}

现在我的视图控制器不再是TableViewController,而是一个ViewController a TableView as like:





所以我介绍了一个新的View控制器,这是我觉得我做的是
a hack,不那么优雅,解决方案可能是: / p>

在CDTVC.h中,我添加了以下内容,因此我可以访问
TallyViewController中的数据:

  @protocol TallyViewDataSource 
- (void)setupTallyLabel:(float)tally;
- (NSString *)getTallyMode;
@end

@property(nonatomic,retain)IBOutlet id< TallyViewDataSource>数据源;

在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;

因此,为了解决这个多重继承问题,我决定分配我的
自己的实例CDTVCTable在我的TallyViewController.m:

   - (void)viewDidLoad 
{
[super viewDidLoad];
//在加载视图之后执行任何其他设置。
_CDTVCTable = [[CDTVC alloc] init];
_CDTVCTable.dataSource = self;
}

- (void)loadTally
{
if(managedObjectContext){
NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@Entry];
request.sortDescriptors = @ [[NSSortDescriptor sortDescriptorWithKey:@dateCreatedascending: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]; //< ----不得不添加这个来刷新本地表。
}



我还必须实现所有的表视图代理, b $ b我的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];
}

所以问题是,有一个更优雅的方式来实现这个
委托和数据源。我必须承认我对代表的掌握和
数据源是弱的,所以我不能确定以一个更好的方式概述。

解决方案

如果你需要/想将静态视图元素与UITableview混合在一起,那么我发现通常最容易添加容器视图到您的ViewController并连接一个外部UITableview到它。



将静态ViewController的转发数据通过Segue发送到UITableView,并返回使用委托,让静态ViewController知道在UITableview中发生了什么。


I want to re-write a view I made in my app to improve the layout. Originally I implemented a TableViewController that uses CoreData as its source. This view worked well for me until I needed to add more views in the TableViewController that would act indipendent of the table and don't scroll out of the screen as more rows are added. The initial implemetnation is as follows based on the apple guide to 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

In my TableViewController, called CDTVC.h, I created a subclass that inherits from CoreDataTableViewController:

@interface CDTVC : CoreDataTableViewController
    @property (nonatomic, copy) NSString *status;
    @property (nonatomic, copy) NSString *totalTally;
    @property (nonatomic, retain) IBOutlet UILabel *tallyDisplayLabel;
@end

In my 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
}

Per guidelines, I need to implement this myself as it is not handled by the parent:

#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;
}

So now my view controller is no longer the TableViewController, but a ViewController that contains a TableView as such:

So I introduced a new View Controller, and this is where I feel what I did is a hack and not quite as elegant as the solution could be:

In CDTVC.h, I added the following so I can access data in the TallyViewController:

@protocol TallyViewDataSource
    -(void)setupTallyLabel:(float) tally;
    -(NSString *) getTallyMode;
@end

@property (nonatomic, retain) IBOutlet id <TallyViewDataSource> dataSource;

In CDTVC.m, I added the following:

@synthesize dataSource = _dataSource;

I moved loadTally implementation to TallyViewController.

TallyViewController.h now has to inherit from UIViewController, which means I cannot inherit from CoreDataViewController anymore:

@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;

So to work around this multiple inheritance issue, I decided to allocate my own instance of CDTVCTable in my TallyViewController.m:

- (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.
}

I also had to implement all of the table view delegates but redirect them to my CDTVCTable, where as before I only had to implement 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];
}

So the question is, is there a more elegant way to implement this with delegates and data sources. I have to admit my grasp on delegates and datasources is weak so I am not sure to outline this in a better way.

解决方案

If you need / want to mix static views elements with a UITableview, then I find it's usually easiest to add a container view to your ViewController and connect an external UITableview to it.

Send the forward data from your static ViewController via the Segue to the UITableView and in return use a delegate to let the static ViewController know what happened in the UITableview.

这篇关于CoreData TableView里面的UIViewController的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆