XMPP介绍二:Core Data

本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。

上一节,介绍了实现XMPP所必须的服务器及数据库搭建工作,如果感兴趣的话,请查看上一篇博客:XMPP介绍一:服务器及数据库搭建。后端的准备工作介绍完毕,现在来介绍一下,客户端开发XMPP所必须具备的储备知识。XMPP架构在客户端的数据持久化操作是通过Core Data实现的,所以这一节的内容,我将为大家详细的说说Core Data的理论知识及基本使用。

一、Core Data基本介绍

Core Data 是苹果实现的一种数据持久化机制,可以方便的用来对SQLite进行CRUD操作。我们经常使用的第三方库FMDB也是对SQLite进行的数据库操作。Core Data的特点就是不用自己书写SQL语句,只需要手动配置对象模型,Core Data这个框架就会自动的帮助我们完成对象实体的映射工作,说简单一点,就是它会自动的帮助我们生成操作数据库的SQL语句。它可以将OC对象整体映射到数据库表中,也可以将数据库表中的数据映射成OC对象直接取出使用。Core Data的核心思想:ORM。 ORM框架的思想最早起源于Java的Hibernate持久化框架;后来.NET 也出了一套同样的机制,称之为Entity Framework;到了iOS5.0中,就称之为Core Data,其实都是同一个意思。为了说明ORM的中心思想,我绘制了一张分析图,如下:


1. 对象模型: 现在大部分的编程语言都支持面向对象思想,上图中左侧图形就表示实体。

2. 关系模型: 指的就是关系型数据库存储的结构,上图中右侧表结构。

3. Core Data的工作就是负责这两种模型之间的数据切换,方便的完成数据存取(避免了书写那些SQL语句)。


二、Xcode创建模型文件的过程

1. 选择模板



2. 添加实体(点击Add Entity)


3. 添加属性



4. 创建NSManagedObject的子类

默认情况下,利用Core Data取出的实体都是NSManagedObject类型的,能够利用键-值对来存取数据。但是一般情况下,实体在存取数据的基础上,有时还需要添加一些业务方法来完成一些其他任务,那么就必须创建NSManagedObject的子类

4.1 创建子类

4.2 选择模型文件 

 

4.3 选择需要创建子类的实体 


4.4 创建完毕后,就可以看到类的信息(包括分类)


4.5 类中的内容

Employee.h

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

NS_ASSUME_NONNULL_BEGIN

@interface Employee : NSManagedObject

// Insert code here to declare functionality of your managed object subclass

@end

NS_ASSUME_NONNULL_END

#import "Employee+CoreDataProperties.h"

Employee+CoreDataProperties.h

#import "Employee.h"

NS_ASSUME_NONNULL_BEGIN

@interface Employee (CoreDataProperties)

@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) NSNumber *age;
@property (nullable, nonatomic, retain) NSNumber *height;

@end

NS_ASSUME_NONNULL_END

三、Core Data中的核心对象

在完成上述操作后,模型文件就已经处理完毕了,接下来的工作就是创建SQLite数据库,及建立相应的连接关系,完成CRUD等操作,在介绍具体的操作之前,我们先来分析一下Core Data中的核心对象,如下图:



1. NSManagedObjectContext:Core Data的请求上下文,就是利用它来完成CRUD等操作。

2. NSPersistentStoreCoordinator:持久化存储调度器,可以利用它来指定并且创建用来持久化数据的SQLite数据库。

3. NSManagedObjectModel:Core Data操作数据的模型对象,可以将所有的模型文件关联起来(模型文件就是后缀名为xcdatamodeld的里面所有的实体文件)。

4. NSEntityDescription:描述实体中属性的详细信息。

有了以上的分析,我们就可以用代码来实现上面一系列的流程工作。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupContext];
}

- (void)setupContext {
    // 创建上下文对象
    self.context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    
    // 创建一个模型对象,nil参数表示会将所有模型文件 关联起来
    NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
    
    // 持久化存储调度器
    NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    
    // 存储数据库路径
    NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *sqlitePath = [document stringByAppendingPathComponent:@"company.sqlite"];
    NSError *error;
    [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlitePath] options:nil error:&error];
    self.context.persistentStoreCoordinator = store;<span style="color:#00afca;">
}</span>

四、利用Core Data完成CRUD操作

1. Create(增加操作)

- (IBAction)addRecord:(id)sender {
    
    Employee *employee = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:self.context];
    employee.name = @"kimmi";
    employee.age = @23;
    employee.height = @1.60;
    
    NSError *error;
    [self.context save:&error];
    if (error) {
        NSLog(@"保存失败");
    } else {
        NSLog(@"保存成功");
    }
}

注:Core Data的增、删、改操作,最终都需要执行 NSManagedObjectContext实例对象的save方法。在调用save方法之前执行的操作全是在内存中执行的,而只有save操作才会将数据的变更同步到SQLite中!

2. Delete (删除操作)

- (IBAction)deleteRecord:(id)sender {
    // 1. 先获取指定对象
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
    
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@", @"jason"];
    request.predicate = pre;
    NSArray *items = [self.context executeFetchRequest:request error:nil];
    
    // 2. 先删除内存中的数据
    for (Employee *emp in items) {
        [self.context deleteObject:emp];
    }
    
    // 3. 同步到数据库
    [self.context save:nil];
}

3. Update (更新操作)

- (IBAction)updateRecord:(id)sender {
    // 1. 先获取指定对象
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
    
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@", @"rose"];
    request.predicate = pre;
    NSArray *items = [self.context executeFetchRequest:request error:nil];
    
    // 2. 修改内存中的数据
    if (items.count > 0) {
        Employee *emp = [items firstObject];
        emp.age = @(24);
        emp.height = @(1.83);
    }
    
    // 3. 同步到数据库
    [self.context save:nil];
}

4. R etrieve (查询操作)

- (IBAction)searchRecords:(id)sender {
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
    
    // 1. 过滤条件(精确查找)
//    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@", @"jason"];
//    request.predicate = pre;
    
    // 2. 过滤条件(大小查找)
//    NSPredicate *pre = [NSPredicate predicateWithFormat:@"height > %@ and age > %@", @(1.0), @(20)];
//    request.predicate = pre;
    
    // 3. 分页查询
//    request.fetchOffset = 4;
//    request.fetchLimit = 2;
    
    NSError *error;
    // 查询结果
    NSArray *items = [self.context executeFetchRequest:request error:&error];
    
    if (error) {
        NSLog(@"查询失败");
    } else {
        for (Employee *employee in items) {
            NSLog(@"name:%@, age:%@, height:%@", employee.name, employee.age, employee.height);
        }
    }
}

- (IBAction)fuzzySearch:(id)sender {
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
    
    // 1. 匹配开头
//    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name beginswith %@", @"ro"];
//    request.predicate = pre;
    
    // 2. 匹配结尾
//    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name endswith %@", @"mi"];
//    request.predicate = pre;
    
    // 3. contains
//    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name contains %@", @"m"];
//    request.predicate = pre;
    
    // 4. like
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name like %@", @"*m*"];
    request.predicate = pre;
    
    NSError *error;
    // 查询结果
    NSArray *items = [self.context executeFetchRequest:request error:&error];
    
    if (error) {
        NSLog(@"查询失败");
    } else {
        for (Employee *employee in items) {
            NSLog(@"name:%@, age:%@, height:%@", employee.name, employee.age, employee.height);
        }
    }
}

5. 处理多表关联的问题

5.1 我们在原来的模型上面,再建立一个Department实体


5.2 在Employee表中建立关联,即每一个员工隶属于某一个部门(depart这个Relationship)


5.3 建立完成这个关联关系后,我们再来看看Employee+CoreDataProperties.h这个文件,可以明显的看出,

多了一个depart对象属性。

#import "Employee.h"

NS_ASSUME_NONNULL_BEGIN

@interface Employee (CoreDataProperties)

@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) NSNumber *age;
@property (nullable, nonatomic, retain) NSNumber *height;
@property (nullable, nonatomic, retain) NSString *city;
@property (nullable, nonatomic, retain) Department *depart;

@end

NS_ASSUME_NONNULL_END


5.4 利用Core Data完成多表关联的操作

- (IBAction)queryRecords:(id)sender {
    // 查询ios部门的员工
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
    
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"depart.name = %@", @"ios"];
    request.predicate = pre;
    
    NSError *error;
    // 查询结果
    NSArray *items = [self.context executeFetchRequest:request error:&error];
    
    if (error) {
        NSLog(@"查询失败");
    } else {
        for (Employee *employee in items) {
            NSLog(@"name:%@, age:%@, height:%@", employee.name, employee.age, employee.height);
        }
    }
}
注意到,NSPredicate中的过滤条件是 depart.name, 它就是直接操作了Employee对象中的depart对象的name属性。

这样,就不用自己书写数据库关联表的SQL语句了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋恨雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值