博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS之coreData的原理和使用以及coreData中的多线程问题(二)
阅读量:4289 次
发布时间:2019-05-27

本文共 8061 字,大约阅读时间需要 26 分钟。

 原理:

CoreDataiOS4.0的时候出来的。

我们的Sqlite支持的是.sqlite类型的文件而我们的CoreData支持的文件类型分为三大类:

第一是Sqlite类文件,第二是binary文件(二进制),第三个是XML类文件

  

      managed object context(管理对象的上下文,有时直接叫"Context")。managed object context就像是一个关卡,通过它可以访问框架底层的对象——这些对象的集合我们称之为"persistence stack"(数据持久栈)。 managed object context作为程序中对象和外部的数据存储的中转站(桥梁)。栈的底部是persistence object stores(持久化数据存储),managed object context也就是数据集的一个映射,所有的操作都要经过他,他不是真实数据,但是可以影响真实数据。

      

          Core Data框架中模型对象(Model objects)常被称为“被管理对象”(Managed objects)。所有的被管理对象都要通过上下文进行注册。使用上下文,你可以在对象图中添加、删除对象,并记录对象的更改(包括单个对象,或是对象间 的关系)。记录更改后就能支持撤销和重做的功能。同时,上下文还能保证关系更改后对象图的完整性。是继承自NSManageObject的;

    如果你想要保存所做的修改, 上下文会保证对象的有效性。在验证有效性后,更改会被写入到persistent store(持久化存储层)中。你在程序中的添加和删除动作都会被作用在存储的数据中。

      对于数据存储(perstance store)中的每个对象,对应的都有唯一的一个被管理对象(managed object)和上下文相关联

      要使用上下文来获取数据,你需要创建相应的请求(Fetch request)。 Fetch request对象包含你想获取的对象的描述(把模型中的实体放进去就可包含实体对象的描述)。

       在程序中,你将Fetch Request这个请求发送给上下文,上下文就会从相关的数据源中查找符合条件的对象(也可能找不到),并返回。 所有的被管理对象(managed object)都必须在上下文中注册,因此通过fetch request获得的对象自动被注册。但如前所述,每个在持久存储层(persistence store)中的对象都对应一个和上下文相关的被管理对象(managed object),因此,如果在上下文中已经存在了fetch request要取的对象,那么这个被管理对象将被返回。

NSFetchRequest是从我们的ManagedObjectContext中读取数据的,并不是向底层的文件读取。

            Core Data追求高执行效率。 它是“需求驱动”的,因此只会创建你确实需要的对象。对象图不需要保留所有在数据存储层中的对象。单纯指定数据持久层的动作不会将其中所有的数据放到上下 文中去。 当你想从数据存储层中获取某些对象的时候,你只会得到那些你请求的(有点罗嗦,总的意思就是需要时获取,获取的就是需要的)。如果你不在需要这个对象的时 候,默认情况下它会被释放。(当然,只是释放这个对象,而不是从对象图中移除该对象)。

       

持久化存储助理(Persistent Store Coordinator)

    程序中的对 象和外部存储的数据通过Core Data框架中的一系列对象进行协调,这一系列的对象总的被称为持久存储栈(Persistence stack)。在栈顶是被管理对象上下文(Managed object context),而栈底是持久化对象存储层(Persistence object store)。在它们之间就是持久化存储助理。

    事实上,持久化存储助理定义了一个栈。从设计方面考虑,它就是可以作为上下 文的”外观“, 这样多个数据存储(Persistence store)看起来就像是一个。 然后上下文就可以根据这些数据存储来创建对象图了(上下文根据多个持久化数据存储创建对象图)。持久化存储助理智能关联一个被管理对象的模型。如果你像要把不同的实体放到不同的存储中去,就需要为你 的模型实体做“分区”,方式是通过定义被管理对象模型的configurations。

      

持久化存储(Persistent Stores)

    持久化存储是和单独的一个文件或外部的数据关联的,它负责将数据和上下文中的对象进行对应。通常,需要你直接和持久化对象存储打交道的地方,就是指定新的、 和程序进行关联的外部数据的存储位置(例如,当用户打开或保存一个文档)。大多数需要访问持久化存储的动作都由上下文来完成。

     被管理对象模型是 NSManagedObjectModel的实例。它描述了你在程序中使用的实体的概要信息。

     entity实体模型包含了NSEntityDescription对象,NSEntityDescription对象指代了模型的实体。NSEntityDescription 对象可包含NSAttributeDescription对象(指代实体的attribute)和NSRelationshipDescription对 象(指代实体间的relationship)。实体也可能包含fetched属性,该属性由NSFetchedPropertyDescription指 代,模型中有对应的fetch请求的模板,fetch请求由NSFetchRequest所指代。

      实体的继承和类 的继承很类似,当然,也同样有用。 如果你有若干个相似的实体,就可以抽离出它们的共有特性作为一个“父实体”,就省去了在多个实体中都指定相同的属性。

总结:coredata框架中的一系列协调外部数据和程序中的对象的对象集合我们可以看作数据持久栈;栈的最上层是管理对象上下文,是对外部数据集的一个映射,他不是真实的数据,但是所有的coredata数据操作都要经过他;栈的底部是持久化对象存储,是和单独的一个文件或外部的数据关联的,它负责将数据和上下文中的对象进行对应

比如读取数据:

NSFetchRequest它会告诉我们他要获取哪个表(一个实体相当于一张表),

// 1.FectchRequest 创建抓取请求对象

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

他不跟底层的类联系,他只和ManagedObjectContext联系他是对ManagedObjectContext的一个操作,

ManagedObjectContext可以有一个,也可以有多个,它可以对应多个文件,也可以对应一个文件,

NSPersistentStoreCoordinator可以从多个文件中整理出来数据拿给ManagedObjectContext。NSFetchRequest是从我们的ManagedObjectContext中读取数据的,并不是向底层的文件读取

===================================

1.实现过程

managed object context把这些变化传递给持久化存储协调器,让它把改变传递给store。持久化存储协调器协调store(是一个SQL存储器)把我们新插入的对象写入磁盘中的SQL数据库里。NSPersistentStore类管理着和SQLite的真正交互,并且生成需要被执行的SQL代码。持久化存储协调器的角色只是简单的协调store和context之间的交互。

2.

当所有组件绑定在一起,我们把它们称为Core Data Stack. 这种堆栈有两个主要部分。一部分是关于对象图管理。第二部分是关于持久化的,

3.

对象图管理是你的应用中模型层逻辑存在的地方。模型层对象存在于一个context里。在大多数设置中,只有一个context,所有的对象都放在这个context中。Core Data支持多个context。

4.

+ (id)insertNewObjectForEntityForName:(NSString *)entityName 

               inManagedObjectContext:(NSManagedObjectContext *)context

+
(
NSString
*
)
entityName
{
  
return
@
Item
;
}
 
+
(
instancetype
)
insertNewObjectInManagedObjectContext
:
(
NSManagedObjectContext
*
)
moc
;
{
  
return
[
NSEntityDescription
insertNewObjectForEntityForName
:
[
self
entityName
]
                                        
inManagedObjectContext
:
moc
]
;
}
//插入对象
Item *rootItem = [Item insertNewObjectInManagedObjectContext:managedObjectContext];

现在在我们的managed object context里有了一个唯一的item. context知道这个新插入的被管理对象,这个被管理对象rootItem也知道这个context(它有 -managedObjectContext方法)。

 //保存改变

//加入第二个item

Item *item = [Item insertNewObjectInManagedObjectContext:managedObjectContext];

item.parent = rootItem;
item.title = @"footItem";

//保存item,当根Item对象创建并保存后,我们可以获取它的NSManagedObjectID。这是一个不透明的对象,只代表根Item对象。我们可以把它保存到NSUserDefaults

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

[defaults setURL:rootItem.managedObjectID.URIRepresentation forKey:@"rootItem"];

//获取对象

//获取所有子items对象

NSOrderedSet*children=rootItem.children;

5.

当你获取一种关系(比如父子关系),下面三种情况中的一个会发生: 

 ( 1 ) 这个对象已经在context中,获取对象基本上没有开销。

(2)这个对象不在context中,但是从store中获取过这个对象,持久化存储协调器缓存了它的值。有一些开销。

(3)当这个对象被context和持久化存储协调器都第一次访问,它需要被store从SQLite数据库中取出来。这种情况开销最大。

6.封装的方法

#import "PersistentStack.h"

@interface PersistentStack ()

@property (nonatomic,readwrite)NSManagedObjectContext* managedObjectContext;

@property (nonatomic,readwrite)NSManagedObjectContext* backgroundManagedObjectContext;

@property (nonatomic)NSURL* modelURL;

@property (nonatomic)NSURL* storeURL;

@end

@implementation PersistentStack

- (id)initWithStoreURL:(NSURL*)storeURL modelURL:(NSURL*)modelURL

{

    self = [superinit];

    if (self) {

        self.storeURL = storeURL;

        self.modelURL = modelURL;

        [selfsetupManagedObjectContexts];

    }

    return self;

}

- (void)setupManagedObjectContexts

{

    self.managedObjectContext = [selfsetupManagedObjectContextWithConcurrencyType:NSMainQueueConcurrencyType];

    self.managedObjectContext.undoManager = [[NSUndoManageralloc]init];

    self.backgroundManagedObjectContext = [selfsetupManagedObjectContextWithConcurrencyType:NSPrivateQueueConcurrencyType];

    self.backgroundManagedObjectContext.undoManager =nil;

    [[NSNotificationCenterdefaultCenter]

            addObserverForName:NSManagedObjectContextDidSaveNotification

                        object:nil

                         queue:nil

                    usingBlock:^(NSNotification* note) {

        NSManagedObjectContext *moc =self.managedObjectContext;

        if (note.object != moc) {

            [moc performBlock:^(){

                [moc mergeChangesFromContextDidSaveNotification:note];

            }];

        }

     }];

}

- (NSManagedObjectContext *)setupManagedObjectContextWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType

{

    NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContextalloc]initWithConcurrencyType:concurrencyType];

    managedObjectContext.persistentStoreCoordinator =

            [[NSPersistentStoreCoordinatoralloc]initWithManagedObjectModel:self.managedObjectModel];

    NSError* error;

    [managedObjectContext.persistentStoreCoordinatoraddPersistentStoreWithType:NSSQLiteStoreType

                                                                  configuration:nil

                                                                            URL:self.storeURL

                                                                        options:nil

                                                                          error:&error];

    if (error) {

        NSLog(@"error: %@", error.localizedDescription);

        NSLog(@"rm \"%@\"",self.storeURL.path);

    }

    return managedObjectContext;

}

- (NSManagedObjectModel*)managedObjectModel

{

    return [[NSManagedObjectModelalloc]initWithContentsOfURL:self.modelURL];

}

=====================

模式设计:

-(void)main{
1.在子线程中创建一个privateContext;执行增删改查,保存,
02.
self.privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
03.
[self.privateContext setPersistentStoreCoordinator:self.mainContext.persistentStoreCoordinator];
04.
 2.注册通知,回到主线程同步context
05.
[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {
06.
if (note.object == self.privateContext) {
07.
dispatch_async(dispatch_get_main_queue(), ^{
08.
[self.mainContext performBlock:^{
09.
[self.mainContext mergeChangesFromContextDidSaveNotification:note];
10.
}];
11.
});
12.
}
13.
}];
14.
 
15.
//执行耗时的操作(增删改查)
16.
 
17.
//执行完毕
18.
[self.privateContext performBlock:^{
19.
NSError * error = nil;
20.
if ([self.privateContext hasChanges]) {
21.
[self.privateContext save:&error];
22.
23.
}];
24.
}

转载地址:http://qelgi.baihongyu.com/

你可能感兴趣的文章
最简单的基于librtmp的示例:发布(FLV通过RTMP发布)
查看>>
Windows/Linux下引用jar包,并用javac/java编译运行
查看>>
HttpClient使用详解
查看>>
HttpClient详解(一)
查看>>
httpclient 请求http数据,json转map
查看>>
git 常用命令
查看>>
用递归方法建立二叉树
查看>>
用递归方法对二叉树进行先序、中序和后序遍历
查看>>
翻转二叉树
查看>>
逆序链表
查看>>
epoll 使用详解
查看>>
stl 中 set容器用法
查看>>
有序数组求交集
查看>>
文字常量区与栈
查看>>
非阻塞connect 编写方法
查看>>
epoll 边沿触发
查看>>
String类 默认生成的函数
查看>>
Linux 软连接与硬链接
查看>>
视音频数据处理入门:H.264视频码流解析
查看>>
视音频数据处理入门:AAC音频码流解析
查看>>