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. Django——启动项目时报错mysqlclient

    报错内容如下: Watching for file changes with StatReloader Exception in thread django-main-thread: Tracebac ...

  2. wpf 自定义轮播图组件

    轮播图组件代码: [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)][TemplateP ...

  3. MySQL入门到精通(十):SQL优化第一篇(2021最新发布)

    SQL优化 1. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,创建表时N ...

  4. this的二种使用方式

    package com.ht.TestThis; public class TestThisKey { public static void main(String[] args) { // TODO ...

  5. REACT 前端界面提交

    在react项目中安装代理中间件 setupProxy.js文件 const { createProxyMiddleware: proxy } = require('http-proxy-middle ...

  6. vue局部注册

    只能在当前注册它的vue实例中使用,通过某个 Vue 实例/组件的实例选项 components 注册仅在其作用域中可用的组件 var Child = { template: '<div> ...

  7. 探索Native Plugins:开启大模型的技能之门

    前言 上一章节我们了解了一下Semantic Kernnel中Plugins插件的概念以及学习了的 Semantic Kernel 模板插件的创建,本章节我们来学习 Native Plugins 原生 ...

  8. CSP-S2019 题解

    做了这套题,如果是让现在的我当时去考的话应该一共可以有 450 分,格雷码,括号树,树的重心都可以做,树上的数可以有 10 分,Emiya 至少可以有 76 分, 划分也可以有 64 分.看 OIer ...

  9. win10无线网卡不会自动连接

    usb接口的网卡.win10无线网卡不会自动连接. 解决方法: 第一步:在控制面板\网络和 Internet\网络连接中,禁用再启用一次无线网络. 第二步:在 控制面板\硬件和声音\电源选项\选择电源 ...

  10. springboot之日志配置-logback

    springboot之日志配置-logback 1.为什么使用logback logback是springboot默认集成的,是基于Sl4J的日志框架. logback的内核重写了,使得在某些关键路径 ...