7- coreData基本扩展(保存NSArray)

Posted on Posted in iOS, 全部文章

一.文章概要

本篇文章主要是说明”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 类并没有声明要实现,代码运行过程中也没有报错。

我们这里新建了名为”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,我会不时分享和转发一些大牛的技术贴和开源项目.

新浪微博:http://weibo.com/1594425143/profile?topnav=1&wvr=6&is_all=1

GitHub:https://github.com/lilongcnc


发表评论

电子邮件地址不会被公开。 必填项已用*标注