前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「死磕」Core Data——非标准数据类型的保存

「死磕」Core Data——非标准数据类型的保存

作者头像
iOS Development
发布2019-02-14 17:49:09
9760
发布2019-02-14 17:49:09
举报

上一篇写了Core Data的入门,这篇会涉及两部分内容:

  • NSFetchedResultsController的使用。
  • 非标准数据类型的保存。

NSFetchedResultsController的使用

其实这个名字,会引起一定的歧义,光看名字,以为是一个普通的视图控制器,其实它并不继承自UIViewController类。

这个类,仅用于高效地管理从Core Data中取回的数据,供UITableView使用,也就是作为UITableView的数据源而存在的。可能是UITableView在iOS开发中太常用了,所以专门造了这个类,和UITableView搭配使用。

创建一个NSFetchedResultsController

需要使用NSFetchedResultsController,首先初始化,创建一个NSFetchedResultsController对象:

(在这段代码之前,我们已经声明了一个属性@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;

代码语言:javascript
复制
- (void)initializeFetchedResultsController {

    // 这里的kUserEntityName就是你在xcdatamodeld文件的实体名称。
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:kUserEntityName];
    
    // 返回数据的排序规则(最少需要有一个sort descriptor)
    // Need at least one sort descriptor
    NSSortDescriptor *nameSort = [NSSortDescriptor sortDescriptorWithKey:kUserNameKey ascending:YES];
    
    [request setSortDescriptors:@[nameSort]];
    
    // 实例化fetchedResultsController对象
    // 需要利用在此之前已经创建的NSManagedObjectContext对象
    // 最后一个参数,可以复制一个字符串,Core Data会自己设置缓存,以提升性能。
    [self setFetchedResultsController:[[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[SPKManager shareManager].store.context sectionNameKeyPath:nil cacheName:nil]];

     // 设置委托对象
     // 协议中有4个委托方法,用来告诉UITableView,Core Data中的数据有变化
    [self.fetchedResultsController setDelegate:self];
    
    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
        NSLog(@"Failed to initialize FetchedResultsController: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    }
}

以上的初始化方法,会放在UITableViewController类中进行。

为Table View提供数据源

要告诉Table View有多少行数据,利用NSFetchedResultsController的sections属性。

代码语言:javascript
复制
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    id<NSFetchedResultsSectionInfo>sectionInfo = self.fetchedResultsController.sections[section];
    return [sectionInfo numberOfObjects];
}

要拿回具体的某个对象,利用NSFetchedResultsController的objectAtIndexPath:方法:

代码语言:javascript
复制
SPKUser *user = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = user.userName;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@", @(user.userID)];

// 如果没有自定义NSManagedObject子类,就应该类似:NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
监视数据的变化

当Core Data中的数据发生变化时,可以通过 NSFetchedResultsControllerDelegate中的委托方法,方便监视数据的变化,自动更新UI。

实现协议的四个方法

代码语言:javascript
复制
#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller{
    [_tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
    switch (type) {
        case NSFetchedResultsChangeInsert:
              // 插入了section
            [_tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeDelete:
              // 删除了section
            [_tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeMove:
            break;
            
        case NSFetchedResultsChangeUpdate:
            break;
            
        default:
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    switch (type) {
        case NSFetchedResultsChangeInsert:
            // 插入了新对象
            [_tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeDelete:
              // 删除了对象
            [_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeUpdate:
            // 修改了对象
            [self configureCell:[_tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
            
        case NSFetchedResultsChangeMove:
              // 移动了对象 
            [_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [_tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        default:
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [_tableView endUpdates];
}

非标准数据类型的处理

在Core Data中,可以保存数据类型比较有限:

  • Integer 16
  • Integer 32
  • Integer 64
  • Decimal (高精度大数,不会四舍五入,适用于金融领域)
  • Double
  • Float
  • String
  • Boolean
  • Date
  • Binary Data
  • Transformable

如果是非标准数据类型,如何保存?

UIImage、UIColor

UIImage和UIColor这类遵守了NSCoding协议的对象,Core Data会帮你转换为NSData后,保存,取回来,也会帮你从NSData转为相对应的对象。选择Transformable类型即可,

数组,字典

NSArray、NSMutableArray、NSDictionary、NSMutableDictionary也是遵守NSCoding的对象,也可以选择Transformable直接保存。

当然,也可以选择Binary Data

  • 保存前,调用NSKeyedUnarchiver的archivedDataWithRootObject:方法返回NSData类型数据,让Core Data可以对其进行保存;
  • 取回时,用NSKeyedUnarchiver的unarchiveObjectWithData:方法,将取回的NSData数据,转换回数组、字典对象。
结构体

保存结构体,可以选择Transformable类型。

然后在声明属性类型的时候,使用NSValue类型,如@property (nullable, nonatomic, retain) NSValue *imgeRect;

赋值时,进行转化,如下: newUser.imgeRect = [NSValue valueWithCGRect:CGRectMake(0.0, 0.0, 100.0, 100.0)];

获取值的时候,再进行转换,如下: CGRect imageRect = [firstUser.imgeRect CGRectValue];

枚举类型

两种思路:

  • 选择Integer 16,当作一个整数机型保存。(声明的时候,就可以用枚举类型了)。如@property (nonatomic) UserGenderType userGender;
  • 选择Transformable,然后重写get、set方法,进行转换……还是用上面的方法吧,比较简单:)

自定义对象

自定义对象,也有两种思路:

  • 直接定义成xcdatamodeld文件中的一个实体,作为NSManagedObject类的子类,由CoreData直接保存;
  • 如果不定义成实体,需要:
  • 该自定义对象需要遵守NSCoding协议并实现required方法(initWithCoder:方法和encodeWithCoder:方法);
  • xcdatamodeld文件中该特性数据类型选择为Transformable
  • 创建一个NSValueTransformer子类,重写transformedValue:和reverseTransformedValue:方法,手动进行数据类型的转换(本质就是自定义对象和NSData互转)类似如下:
代码语言:javascript
复制
#import "HAEqTransformer.h"
#import "HAEq.h"

// 我的自定义对象是HAEq
@implementation HAEqTransformer

+ (Class)transformedValueClass {
    return [NSData class];
}

- (id)transformedValue:(id)value {
    if (!value) {
        return nil;
    }
    
    if ([value isKindOfClass:[NSData class]]) {
        return value;
    }
    
    HAEq *eq = (HAEq *)value;
    // 将自定义对象转换成NSData
    NSData *dataFromEq = [NSKeyedArchiver archivedDataWithRootObject:eq];
    
    return dataFromEq;
}

- (id)reverseTransformedValue:(id)value {
    NSData *data = (NSData *)value;
    // 将NSData对象转换为自定义对象
    HAEq *eq = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    return eq;
}
@end

所以,利用Core Data保存非标准数据类型,以上都基本涉及了。

End

以上,就是Core Data中的NSFetchedResultsController的使用、以及非标准数据类型的保存方法。

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.05.06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NSFetchedResultsController的使用
    • 创建一个NSFetchedResultsController
      • 为Table View提供数据源
        • 监视数据的变化
        • 非标准数据类型的处理
          • UIImage、UIColor
            • 数组,字典
              • 结构体
                • 枚举类型
                  • 自定义对象
                  • End
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                  http://www.vxiaotou.com