Objective-C (OC) 中使用 Core Data 是iOS应用开发中管理模型层对象的一种有效工具。Core Data 使用 ORM (对象关系映射) 技术来抽象化和管理数据。这不仅可以节省时间,还能减少编程错误。以下是使用 Core Data 的详细介绍,包括示例代码,以及深入底层的一些分析。

基本概念

  1. 持久化容器 (NSPersistentContainer): iOS 10 引入的,封装了 Core Data 栈的设置,包括托管对象模型 (NSManagedObjectModel),持久化存储协调器 (NSPersistentStoreCoordinator),和上下文 (NSManagedObjectContext)。

  2. 托管对象模型 (NSManagedObjectModel): 描述应用的数据模型,包括实体(Entity)和这些实体之间的关系。

  3. 持久化存储协调器 (NSPersistentStoreCoordinator): 负责协调托管对象上下文和持久化存储。

  4. 上下文 (NSManagedObjectContext): 用于在内存中管理对象。执行创建、读取、更新、删除操作时,这些更改暂时只发生在上下文中,直到保存更改到持久层。

使用示例

以下是一个简单的使用 Core Data 创建和查询对象的示例:

步骤 1: 配置数据模型

首先,通过 Xcode 的 Data Model Editor 创建数据模型文件(.xcdatamodeld)。假设定义了一个 Person 实体,有 nameage 两个属性。

步骤 2: 设置持久化容器

在 AppDelegate 中设置持久化容器:

#import <CoreData/CoreData.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (readonly, strong) NSPersistentContainer *persistentContainer;

- (void)saveContext;

@end

@implementation AppDelegate

@synthesize persistentContainer = _persistentContainer;

// 懒加载 persistentContainer
- (NSPersistentContainer *)persistentContainer {
// 如果容器已经被初始化了,直接返回
if (_persistentContainer != nil) {
return _persistentContainer;
} // 使用名为 MyModel 的模型文件创建容器
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"MyModel"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
// 错误处理,实际应用中应该替换为更合适的错误处理
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}];
return _persistentContainer;
}
@end

步骤 3: 使用 Core Data 新增和查询

在合适的地方(如 ViewController)进行数据的新增和查询:

#import "AppDelegate.h"
#import <CoreData/CoreData.h> - (void)insertNewPersonWithName:(NSString *)name age:(int)age {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = appDelegate.persistentContainer.viewContext; // 创建新的 Person 实体对象
NSManagedObject *newPerson = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
[newPerson setValue:name forKey:@"name"];
[newPerson setValue:@(age) forKey:@"age"]; NSError *error = nil;
// 保存到持久层
if (![context save:&error]) {
NSLog(@"保存失败: %@, %@", error, error.userInfo);
}
} - (NSArray *)fetchPersons {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = appDelegate.persistentContainer.viewContext; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"]; NSError *error = nil;
NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
if (!results) {
NSLog(@"查询失败: %@, %@", error, error.userInfo);
}
return results;
}

深入分析

Core Data 的底层使用了 SQLite 作为默认的持久化方式(尽管你可以选择内存或者自定义解决方案),但开发者无需直接与数据库交互,所有的操作都是通过上述的对象和 API 完成。Core Data 框架负责转换这些操作为 SQLite 命令并执行。

Core Data 性能优化

  • 批量请求: iOS 8 引入了批量删除和更新,这样可以在不加载数据到内存的情况下直接在持久层执行操作,极大提升效率。

  • 预获取: 对于频繁访问的关联对象,可以使用预获取来减少查询次数。

  • 轻量级迁移: 对于数据模型的更改,通过轻量级迁移避免手动处理数据结构变动。

封装

对于Core Data的使用,进行二次封装可以提高代码的复用性,让外部调用变得更加简洁。我们可以创建一个单例类CoreDataManager来管理Core Data的常见操作,比如增删改查。

首先,你需要确保你的数据模型(.xcdatamodeld文件)已经设置好,举个例子,这里假设我们有一个Person的Entity,它有两个属性:name(String类型)和age(Int16类型)。

步骤 1: 创建Core Data管理类

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h> @interface CoreDataManager : NSObject @property (readonly, strong) NSPersistentContainer *persistentContainer;
+ (instancetype)sharedManager;
- (void)saveContext;
- (void)insertPersonWithName:(NSString *)name age:(NSNumber *)age completion:(void(^)(BOOL success, NSError *error))completion;
- (void)fetchAllPersons:(void(^)(NSArray *persons, NSError *error))completion; @end @implementation CoreDataManager + (instancetype)sharedManager {
static CoreDataManager *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[self alloc] init];
});
return sharedManager;
} - (NSPersistentContainer *)persistentContainer {
@synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"YourModelName"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}];
}
}
return _persistentContainer;
} - (void)saveContext {
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSError *error = nil;
if ([context hasChanges] && ![context save:&error]) {
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
} - (void)insertPersonWithName:(NSString *)name age:(NSNumber *)age completion:(void(^)(BOOL success, NSError *error))completion {
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSManagedObject *newPerson = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
[newPerson setValue:name forKey:@"name"];
[newPerson setValue:age forKey:@"age"]; NSError *error = nil;
if (![context save:&error]) {
NSLog(@"Error saving context: %@, %@", error, error.userInfo);
completion(NO, error);
} else {
completion(YES, nil);
}
} - (void)fetchAllPersons:(void(^)(NSArray *persons, NSError *error))completion {
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"]; NSError *error = nil;
NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
if (error) {
NSLog(@"Failed to fetch persons: %@, %@", error, error.userInfo);
completion(nil, error);
} else {
completion(results, nil);
}
} @end

使用封装的CoreDataManager

这里展示如何使用CoreDataManager进行数据操作:

// 插入新的Person对象
[[CoreDataManager sharedManager] insertPersonWithName:@"John Doe" age:@25 completion:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"Person added successfully");
} else {
NSLog(@"Failed to add person: %@", error.localizedDescription);
}
}]; // 获取所有的Person对象
[[CoreDataManager sharedManager] fetchAllPersons:^(NSArray * _Nonnull persons, NSError * _Nonnull error) {
if (error) {
NSLog(@"Failed to fetch persons: %@", error.localizedDescription);
} else {
for (NSManagedObject *person in persons) {
NSString *name = [person valueForKey:@"name"];
NSNumber *age = [person valueForKey:@"age"];
NSLog(@"Fetched person: %@, age: %@", name, age);
}
}
}];

通过上面的封装,我们只需调用简单的方法就可以完成对Person对象的增删改查操作,而不用关心Core Data的具体实现细节。这大大提高了代码的可读性和可维护性。

总结

Core Data 是一个功能强大的框架,通过封装复杂的底层细节,使得数据管理变得更加简单。高效地使用 Core Data 必须理解其背后的原理,并遵循最佳实践来设计应用。

iOS开发基础135-Core Data的更多相关文章

  1. iOS开发——总结篇&IOS开发基础知识

    IOS开发基础知识 1:Objective-C语法之动态类型(isKindOfClass, isMemberOfClass,id) 对象在运行时获取其类型的能力称为内省.内省可以有多种方法实现. 判断 ...

  2. iOS开发基础-九宫格坐标(6)

    继续对iOS开发基础-九宫格坐标(5)中的代码进行优化. 优化思路:把字典转模型部分的数据处理操作也拿到模型类中去实现,即将 ViewController 类实现中 apps 方法搬到 WJQAppI ...

  3. iOS开发基础-九宫格坐标(2)之模型

    在iOS开发基础-九宫格(1)中,属性变量 apps 是从plist文件中加载数据的,在 viewDidLoad 方法中的第20行.26行中,直接通过字典的键名来获取相应的信息,使得 ViewCont ...

  4. iOS开发基础-图片切换(3)之属性列表

    延续:iOS开发基础-图片切换(2),对(2)里面的代码用属性列表plist进行改善. 新建 Property List 命名为 Data 获得一个后缀为 .plist 的文件. 按如图修改刚创建的文 ...

  5. iOS开发过程中使用Core Data应避免的十个错误

    原文出处: informit   译文出处:cocoachina Core Data是苹果针对Mac和iOS平台开发的一个框架,主要用来储存数据.对很多开发者来说,Core Data比较容易入手,但很 ...

  6. IOS开发基础知识碎片-导航

    1:IOS开发基础知识--碎片1 a:NSString与NSInteger的互换 b:Objective-c中集合里面不能存放基础类型,比如int string float等,只能把它们转化成对象才可 ...

  7. IOS开发基础环境搭建

    一.目的 本文的目的是windows下IOS开发基础环境搭建做了对应的介绍,大家可根据文档步骤进行mac环境部署: 二.安装虚拟机 下载虚拟机安装文件绿色版,点击如下文件安装 获取安装包:       ...

  8. iOS开发基础-九宫格坐标(5)

    继续在iOS开发基础-九宫格坐标(4)的基础上进行优化. 一.改进思路 1)iOS开发基础-九宫格坐标(4)中 viewDidLoad 方法中的第21.22行对控件属性的设置能否拿到视图类 WJQAp ...

  9. iOS开发基础-九宫格坐标(4)

    对iOS开发基础-九宫格坐标(3)的代码进行进一步优化. 新建一个 UIView 的子类,并命名为 WJQAppView ,将 appxib.xib 中的 UIView 对象与新建的视图类进行关联. ...

  10. iOS开发基础-九宫格坐标(3)之Xib

    延续iOS开发基础-九宫格坐标(2)的内容,对其进行部分修改. 本部分采用 Xib 文件来创建用于显示图片的 UIView 对象. 一.简单介绍  Xib 和 storyboard 的比较: 1) X ...

随机推荐

  1. FFmpeg开发笔记(二十三)使用OBS Studio开启RTMP直播推流

    ​OBS是一个开源的直播录制软件,英文全称叫做Open Broadcaster Software,广泛用于视频录制.实时直播等领域.OBS不但开源,而且跨平台,兼容Windows.Mac OS.Lin ...

  2. StackOverFlow & OutOfMemory

    StackOverFlow & OutOfMemory 两者都为 Error,广义上的"异常" StackOverflow 通常为 Java 虚拟机栈内存不够,JVM 对方 ...

  3. 二叉树的遍历(BFS、DFS)

    二叉树的遍历(BFS.DFS) 本文分为以下部分: BFS(广度优先搜索) DFS(深度优先搜索) 先序遍历 中序遍历 后序遍历 总结 BFS(广度优先搜索) 广度优先搜索[^1](英语:Breadt ...

  4. Android OpenMAX(二)OMX Component实现基础

    Android OpenMAX IL提供的API位于 frameworks/native/headers/media_plugin/media/openmax ,目录下存放有预定义的类型.组件句柄定义 ...

  5. Android 13 - Media框架(19)- ACodec(一)

    关注公众号免费阅读全文,进入音视频开发技术分享群! 这一节我们将会一起了解 ACodec 的设计方式,在看具体的实现细节前我们要先了解它内部的状态转换机制,这也是ACodec的核心难点之一. 1.AH ...

  6. Windows程序读取不了中文路径问题

    问题描述 今天调试发现win32接口GetFileAttributesW居然不支持中文路径,于是寻找解决方案,找了半天,尝试用boost的fileystem库发现能用,而且boost能跨平台! 不支持 ...

  7. uniapp 小程序分享功能

    上个月在做小程序的项目时,甲方需要给小程序添加个分享的功能,查看uniapp官方文档后,发现uniapp有自带的小程序分享功能(https://uniapp.dcloud.io/api/plugins ...

  8. 《Qt学习系列笔记》--章节索引

    Qt下载.安装及环境搭建:https://www.cnblogs.com/mrlayfolk/p/13111349.html Qt初始化代码基本说明:https://www.cnblogs.com/m ...

  9. Java泛型对象在http请求和响应对象中的封装

    Java泛型对象在http请求和响应对象中的封装 public class MySystemBaseResVo<T> { //注意:类的后面需要带上<T>,否则数据无法封装 p ...

  10. Spring之WebMvcConfigurationSupport

    WebMvcConfigurationSupport是mvc的核心配置.开发spring,了解和掌握这个是必须的. 为了简约篇幅,本文把"WebMvcConfigurationSupport ...