[IOS开发进阶与实战]第二天:使用CoreData 在TabelView中添加实体的思考1

第一遍在写这个简单的APP之前,有些不是很理解.现在简单的回顾一下,也许有更多的收获.


1.首先,我们复选了  CoreData .使用了 CD,我们看看  myCoreData.xcdatemodeld 中的内部.


可以看出,最上面的 Attributes 是一个实体的属性.我们这里设置了 性别,秘密定义,姓名,和生日.我们看右边,最重要的要属Properties 中的几个复选框了,第一个的意思是  可以不再 数据库中存储,Optional 的意思是 可为NULL.

2.我们在上一天中陈述了关于 Coredata的内部机制.关于上下文,请求等的实现方式.在Controllor中,我们只需要调用代理中的方法就可以得到对应的 上下文等.

现在,我们来看看ViewController是如何实现的~

#define  kSelectedtabDefaultsKey @"selected Tab"

enum
{
    kByName,
    kBySecretIdentify,
    
};

@interface HeroListController : UIViewController<UITableViewDelegate,UITableViewDataSource,UITabBarDelegate,NSFetchedResultsControllerDelegate,UIAlertViewDelegate>
@property (weak, nonatomic) IBOutlet UIBarButtonItem *addButton; //增加按钮,.m中解释
@property (weak, nonatomic) IBOutlet UITabBar *heroTapBar;


@property (weak, nonatomic) IBOutlet UITableView *heroTableView; 
- (IBAction)addHero:(id)sender;

@end

我们看看里面的属性和协议.

我们有些不认识 NSFetchedResultsControllerDelegate协议.这个协议 其实就是有关我们的数据库中实体的行改变,实体属性改变所回调所定义的协议.

先看看里面的具体方法

@protocol NSFetchedResultsControllerDelegate

enum {
	NSFetchedResultsChangeInsert = 1,
	NSFetchedResultsChangeDelete = 2,
	NSFetchedResultsChangeMove = 3,
	NSFetchedResultsChangeUpdate = 4
	
};
typedef NSUInteger NSFetchedResultsChangeType; //定义请求改变的类型

/* Notifies the delegate that a fetched object has been changed due to an add, remove, move, or update. Enables NSFetchedResultsController change tracking.
	controller - controller instance that noticed the change on its fetched objects
	anObject - changed object
	indexPath - indexPath of changed object (nil for inserts)
	type - indicates if the change was an insert, delete, move, or update
	newIndexPath - the destination path for inserted or moved objects, nil otherwise
	
	Changes are reported with the following heuristics:

	On Adds and Removes, only the Added/Removed object is reported. It's assumed that all objects that come after the affected object are also moved, but these moves are not reported. 
	The Move object is reported when the changed attribute on the object is one of the sort descriptors used in the fetch request.  An update of the object is assumed in this case, but no separate update message is sent to the delegate.
	The Update object is reported when an object's state changes, and the changed attributes aren't part of the sort keys. 
*/
@optional //检测实体将会正价,删除,移动或者更新的代理
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath;

/* Notifies the delegate of added or removed sections.  Enables NSFetchedResultsController change tracking.

	controller - controller instance that noticed the change on its sections
	sectionInfo - changed section
	index - index of changed section
	type - indicates if the change was an insert or delete

	Changes on section info are reported before changes on fetchedObjects. 
*///增加或者删除行将会出发的代理
@optional
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type;
//选择行或者实体将要触发的代理
/* Notifies the delegate that section and object changes are about to be processed and notifications will be sent.  Enables NSFetchedResultsController change tracking.
   Clients utilizing a UITableView may prepare for a batch of updates by responding to this method with -beginUpdates
*/
@optional //所有的行和实体都将改变才触发的代理
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller;
//检测  所有的行和实体将要改变 将会触发的代理
/* Notifies the delegate that all section and object changes have been sent. Enables NSFetchedResultsController change tracking.
   Providing an empty implementation will enable change tracking if you do not care about the individual callbacks.
*/
@optional  //所有的行和实体已经改变将会触发的实体
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller;

/* Asks the delegate to return the corresponding section index entry for a given section name.	Does not enable NSFetchedResultsController change tracking.
    If this method isn't implemented by the delegate, the default implementation returns the capitalized first letter of the section name (seee NSFetchedResultsController sectionIndexTitleForSectionName:)
    Only needed if a section index is used.
*/
@optional //要求代理针对我们已经选择的section的name返回 正确的 实体.
- (NSString *)controller:(NSFetchedResultsController *)controller sectionIndexTitleForSectionName:(NSString *)sectionName 

3.ViewController.m中的 前一部分的解释说明

#import "HeroListController.h"

#import "LCAppDelegate.h"

static NSString *CellIdentifier = @"HeroCell";

@interface HeroListController ()

@property(nonatomic,strong,readonly)NSFetchedResultsController *fetchedResultsController;
//定义一个  私有的只读的  NSFetchedResultsController 来引用 appDelegate中的   上下文等内容

@end

@implementation HeroListController

@synthesize fetchedResultsController = _fetchedResultsController;



- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self.heroTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier];
    
//这句话是极其关键的一句.为什么这样说呢? 因为在IOS6之后,我们如果定义一个  Cell 类型,必须使用这样的一个方法,来确//定我们的 cell归属类或者归属的xib文件. (下面着重解释)
    self.navigationItem.leftBarButtonItem = self.editButtonItem; //左边 barButton 设置成编辑按钮
    //对我们的yabbarItem进行 记忆,但是我没发现有什么不同.
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    NSInteger selectedTab = [defaults integerForKey:kSelectedtabDefaultsKey];
    
    UITabBarItem *item = [self.heroTapBar.items objectAtIndex:selectedTab];
    
    [self.heroTapBar setSelectedItem:item];
     NSLog(@"解析成功 %d",selectedTab);
    
    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) {
        UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"error loading" message:@"view did load error" delegate:self cancelButtonTitle:@"e ,,,," otherButtonTitles:nil];
        
        [alertView show];
        
        
        
    }
    
    //Users Defaluts 来记忆~
    
}

4.IOS6之后新引进的关于  自定义cell的使用方法

    [self.heroTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier];
    
//这句话是极其关键的一句.为什么这样说呢? 因为在IOS6之后,我们如果定义一个  Cell 类型,必须使用这样的一个方法,来确//定我们的 cell归属类或者归属的xib文件. 

我们先去看看官方文档

1).- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);  //这是我们之前使用的样式.
2).- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);

3).- (void)registerNib:(UINib *)nib forHeaderFooterViewReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
4_.- (void)registerClass:(Class)aClass forHeaderFooterViewReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
1.)这是我们以前经常使用的方法.

if(cell == nil)

{

VIewCel了*cell = [  alloc]...

}

2-4)都是我们新引进的方法.我们要不引入一个 cell的类,要不引入一个 xib文件.在viewDidLoad中进行初始化,那么我们在  cellfor...那个协议的实现中就不必要 if(cell == nil)那样判断了,只需要 初始化一个cell就可以了,简便快捷.

代码中我都有体现.大家可以注意一下


5.我们仔细看看 cell的绘制方法

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
      NSLog(@"[[self.fetchedResultsController sections] count]%d",[[self.fetchedResultsController sections] count]);
    return [[self.fetchedResultsController sections] count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    id<NSFetchedResultsSectionInfo>sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    
    NSLog(@"[sectionInfo numberOfObjects]%d",[sectionInfo numberOfObjects]);
    
    return [sectionInfo numberOfObjects];
    
    
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
   // UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    NSManagedObject *aHero = [self.fetchedResultsController objectAtIndexPath:indexPath];
    NSInteger tab = [self.heroTapBar.items indexOfObject:self.heroTapBar.selectedItem];
    
    switch (tab) {
        case kByName:
            cell.textLabel.text = [aHero valueForKey:@"name"];
            cell.detailTextLabel.text = [aHero valueForKey:@"secretIdentify"];
            break;
            case kBySecretIdentify:
            cell.textLabel.text = [aHero valueForKey:@"secretIdentify"];
            cell.detailTextLabel.text = [aHero valueForKey:@"name"];
            break;
    
    }
    
    // Configure the cell...
    
    return cell;
}

1.)行的多少的获得.我们直接调用self.fetchedResultsController 获得 sections 的数组.然后count就ok,有同学会问,那里面关键的  self.fetchedResultsController 方法是从哪里获得的?好吧,我下面就给出来源.其实还在此.m方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
      NSLog(@"[[self.fetchedResultsController sections] count]%d",[[self.fetchedResultsController sections] count]);
    return [[self.fetchedResultsController sections] count];
}

我们还记得我们在私有属性中定义了一个 fetchedResultController .我们重新定义了get方法.

代码如下:

-(NSFetchedResultsController *)fetchedResultsController
{
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    //还记得我们的.m方法中的 导入接口 

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];//我们首先定义了一个请求.
    
    LCAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    //我们的代理中已经有了关于这个数据库上下文的get方法,我们只需要调用就ok.
    NSManagedObjectContext *managedObjectContext = [appDelegate managedObjectContext];
    //定义一个实体描述对象  entity.把我们的实体名字 比如:Hero 设置成实体名字.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Hero" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];  //为请求设置实体的描述
     
    [fetchRequest setFetchBatchSize:20];//设置接收的每一份数据的大小.
    
    NSUInteger tabIndex = [self.heroTapBar.items indexOfObject:self.heroTapBar.selectedItem];
    //user的选择项,针对不同的选择项,我们有不同的排序方式
    if (tabIndex == NSNotFound) {
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        
        tabIndex = [defaults integerForKey:kSelectedtabDefaultsKey];
    }
    
    NSString *sectionKey = nil;
    
    switch (tabIndex) {
        case kByName:
         { NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc]initWithKey:@"name" ascending:YES];
            NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc]initWithKey:@"secretIdentify" ascending:YES];
            NSArray *sortDescriptiors = [[NSArray alloc]initWithObjects:sortDescriptor1  ,sortDescriptor2, nil];
            
            [fetchRequest setSortDescriptors:sortDescriptiors];
            sectionKey = @"name";
            break;
        }
            case kBySecretIdentify:
        {
            NSSortDescriptor *sortDescriptor1 =[[NSSortDescriptor alloc]initWithKey:@"secretIdentify" ascending:YES];
            NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc]initWithKey:@"name" ascending:YES];
             NSArray *sortDescriptiors = [[NSArray alloc]initWithObjects:sortDescriptor1  ,sortDescriptor2, nil];
            
            [fetchRequest setSortDescriptors:sortDescriptiors];
            sectionKey = @"secretIdentify";
        
            break;
        }
        default:
            break;
    }
    //终于创造出我们需要的fetchedResultsController 了~~
    _fetchedResultsController = [[NSFetchedResultsController  alloc]initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:sectionKey cacheName:@"Hero"];
    //只是必须的,我们需要设置代理,因为实现了三个代理,如果我们成功的简历了这个resultController,就必须给予代理~~~要不然,我们的代理方法可是不会回调的哦
    _fetchedResultsController.delegate =self;
    
    return _fetchedResultsController;

}

下面是关于 这个fetchedResultsController 的Delegate 代理的三条协议

-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{//上下文即将改变时候回调,开始更新 tableView
    [self.heroTableView beginUpdates];
    NSLog(@"即将改变数据上下文");
}

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{  //上下文已经改变时候回调,table 更新完整
    [self.heroTableView endUpdates];
    NSLog(@"数据上下文改变完毕");
}

-(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    NSLog(@"Section:-----%lu",(unsigned long)type);
    NSLog(@"sectionIndex %d",sectionIndex);
    switch (type) {  //根据我们的改变(插入或者删除)的类型进行相应的调用方法.方法很简单哦
        case NSFetchedResultsChangeInsert:
            [self.heroTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
            case NSFetchedResultsChangeDelete:
            [self.heroTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
    
}

-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
    NSLog(@"object: %lu------%@",(unsigned long)type,anObject);
    NSLog(@"newIndexpath --%@",newIndexPath);
    switch (type) {  //相应的实体改变进行的回调.
        case NSFetchedResultsChangeInsert:
            [self.heroTableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            case NSFetchedResultsChangeDelete:
            [self.heroTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
    
    }

}



总体来说,section或者 entity的改变 使用的方法都很简单.

我们来整体看看回调的方法,使用的 对象是tableView

- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0);

- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath NS_AVAILABLE_IOS(5_0);



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值