一.文章概要
本篇文章主要是说明"coreData"如何利用"Transformable"类型,保存"NSArray".
整个存储的思路就是在coreData保存时,设置要保存NSArray的属性的类型为'Binary Data(二进制数据)',然后利用NSKeyedArchiver对要保存的NSArray进行转换.因为coreData没有提供可以直接保存NSArray的数据类型 逻辑如下图:
关于NSArray的保存,研究了好久,最终只试验成功了这一种方案,感觉有点不合逻辑,譬如重新创建一个和实体对应的对象类.大家要是有更好的方案的话,希望能够告诉我下,不胜感激!!!
二.准备工作(关于NSKeyedArchiver)
NSKeyedArchiver归档是iOS数据持久化的方式之一.
我们使用NSKeyedArchiver可以归档和恢复NSString、NSArray、NSDictionary、NSSet、NSDate、NSNumber和NSData等基本的Foundation对象。更加具体的看这篇文章:http://blog.csdn.net/jymn_chen/article/details/18893939
三.新增加保存NSArray的属性
第一步,在实体中增加属性
这里属性类型是"Binary Data",应为翻译就是��"二进制数据". 添加完成后如下图:
第二步,生成新的"NSManagedObject"子类文件
和上篇文章相同,不赘述.
四.创建需要保存的对象类
我这里说的对象类型是指的我们正常创建了的继承了NSObject的对象类.而不是我们上文提到coreData模型文件自动生成NSManagedObject Sublcass子类的的例如"Book+CoreDataProperties.h","Book"这些.
还有一点我要提到的是,在最开始的试验保存NSArray时候,想要直接保存上述NSManagedObject Subclass子类,到那时各种尝试始终不行,不是保存的时候报错,就是读取的时候报错
所以,这里即使我们真的要保存一个和之前实体一模一样的类型,也需要再重新创建一个新的对应全部属性的NSObject类
.同时,又因为我们用到了NSKeyedArchiver进行归档,所以同时还需要实现NSCoding 协议中的两个方法,分别是"encodeWithCoder"和"initWithCoder"
但是在实际代码中,我们新建的NSObject 类并没有声明要实现<NSCoing>,代码运行过程中也没有报错。
我们这里新建了名为"BookInfo的子类"具体代码如下:
BookInfo.h:
//
// BookInfo.h
// fmdb
//
// Created by 李龙 on 16/1/5.
// Copyright © 2016年 李龙. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Student.h"
@interface BookInfo : NSObject
@property (nonatomic, assign) NSNumber *bookID;
@property (copy, nonatomic) NSString *bookName;
@property (strong,nonatomic) Student *student;
@end
BookInfo.m:
//
// BookInfo.m
// fmdb
//
// Created by 李龙 on 16/1/5.
// Copyright © 2016年 李龙. All rights reserved.
//
#import "BookInfo.h"
@implementation BookInfo
- (void) encodeWithCoder: (NSCoder *)coder
{
[coder encodeObject:self.bookID forKey:@"bookID"];
// [coder encodeObject:self.bookName forKey:@"bookName"];
[coder encodeObject:self.student forKey:@"student"];
}
- (id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
self.bookID = [aDecoder decodeObjectForKey:@"bookID"];
// self.student = [aDecoder decodeObjectForKey:@"student"];
self.bookName = [aDecoder decodeObjectForKey:@"bookName"];
}
return self;
}
@end
注意:如果你要在BookInfo的对象中保存stduent这个属性,那么按照这种方法,你还需要在创建一个平常的和实体Student对应的Student的对象类
五.保存和读取NSArray
保存NSArray
保存代码如下是:
//插入数据
- (IBAction)insertData{
NSLog(@"插入数据");
//====== 3'
//第一组数据
Student *student = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.managedContext];
student.name = @"张三2";
student.id = @(11);
BookInfo *book = [[BookInfo alloc] init];
book.bookID = @(121);
book.bookName = @"<老人与海2>";
// book.student = student;
// student.book = book;
BookInfo *book1 = [[BookInfo alloc] init];
book1.bookID = @(121);
book1.bookName = @"<老人与海2>";
// book1.student = student;
student.booksArray = [NSKeyedArchiver archivedDataWithRootObject:@[book,book1]];
//第二组数据
Student *student2 = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.managedContext];
student2.name = @"李四2";
student2.id = @(23);
BookInfo *book2 = [[BookInfo alloc] init];
book2.bookID = @(242);
book2.bookName = @"<飞鸟集2222>";
// book2.student = student;
// student2.book = book2;
BookInfo *book22 = [[BookInfo alloc] init];
book22.bookID = @(242);
book22.bookName = @"<飞鸟集22222>";
book22.student = student;
student2.booksArray = [NSKeyedArchiver archivedDataWithRootObject:@[book2,book22]];
//保存,用 save 方法
NSError *error = nil;
BOOL success = [self.managedContext save:&error];
if (!success) {
[NSException raise:@"访问数据库错误" format:@"%@",[error localizedDescription]];
}
}
读取NSArray
图中对应代码如下:
//读取数据库文件
- (IBAction)readData{
NSLog(@"读取数据");
dispatch_async(dispatch_get_main_queue(), ^{
// 初始化一个查询请求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// 设置要查询的实体
request.entity = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:self.managedContext];
//以上代码简写成下边
// NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
// 设置排序(按照age降序)
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"id" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:sort];
// 执行请求
NSError *error = nil;
NSArray *objs = [self.managedContext executeFetchRequest:request error:&error];
if (error) {
[NSException raise:@"查询错误" format:@"%@", [error localizedDescription]];
}
NSLog(@"-----------------------------------");
// 遍历数据
for (Student *stu in objs) {
//获取书的数组
NSArray *bookArr = [NSKeyedUnarchiver unarchiveObjectWithData:stu.booksArray];
NSLog(@"%@",bookArr);
for (BookInfo *book in bookArr) {
NSLog(@"bookInfo:%zd-----%@-----%@",book.bookID,book.bookName,book.student);
}
}
});
}
六.小结
到这里保存NSArray的这种方式就写完了. 大家也可以注意到,这个方法保存数组,数组对象中或者数组对象保存的属性中不能出现NSEntityDescription得到的对象子类.
具体的 Demo 代码可以在我的 GitHub 上找到 Demo地址
我一时间也想不到其他的好方法,希望有其他方法保存NSArray朋友能够分享下.
交流
欢迎大家关注我的微博和我GitHub,我会不时分享和转发一些大牛的技术贴和开源项目.
GitHub:https://github.com/lilongcnc
博客地址:http://www.lilongcnc.cc