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 中设置持久化容器:

  1. #import <CoreData/CoreData.h>
  2. @interface AppDelegate : UIResponder <UIApplicationDelegate>
  3. @property (readonly, strong) NSPersistentContainer *persistentContainer;
  4. - (void)saveContext;
  5. @end
  6. @implementation AppDelegate
  7. @synthesize persistentContainer = _persistentContainer;
  8. // 懒加载 persistentContainer
  9. - (NSPersistentContainer *)persistentContainer {
  10. // 如果容器已经被初始化了,直接返回
  11. if (_persistentContainer != nil) {
  12. return _persistentContainer;
  13. }
  14. // 使用名为 MyModel 的模型文件创建容器
  15. _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"MyModel"];
  16. [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
  17. if (error != nil) {
  18. // 错误处理,实际应用中应该替换为更合适的错误处理
  19. NSLog(@"Unresolved error %@, %@", error, error.userInfo);
  20. abort();
  21. }
  22. }];
  23. return _persistentContainer;
  24. }
  25. @end

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

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

  1. #import "AppDelegate.h"
  2. #import <CoreData/CoreData.h>
  3. - (void)insertNewPersonWithName:(NSString *)name age:(int)age {
  4. AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  5. NSManagedObjectContext *context = appDelegate.persistentContainer.viewContext;
  6. // 创建新的 Person 实体对象
  7. NSManagedObject *newPerson = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
  8. [newPerson setValue:name forKey:@"name"];
  9. [newPerson setValue:@(age) forKey:@"age"];
  10. NSError *error = nil;
  11. // 保存到持久层
  12. if (![context save:&error]) {
  13. NSLog(@"保存失败: %@, %@", error, error.userInfo);
  14. }
  15. }
  16. - (NSArray *)fetchPersons {
  17. AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  18. NSManagedObjectContext *context = appDelegate.persistentContainer.viewContext;
  19. NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
  20. NSError *error = nil;
  21. NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
  22. if (!results) {
  23. NSLog(@"查询失败: %@, %@", error, error.userInfo);
  24. }
  25. return results;
  26. }

深入分析

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管理类

  1. #import <Foundation/Foundation.h>
  2. #import <CoreData/CoreData.h>
  3. @interface CoreDataManager : NSObject
  4. @property (readonly, strong) NSPersistentContainer *persistentContainer;
  5. + (instancetype)sharedManager;
  6. - (void)saveContext;
  7. - (void)insertPersonWithName:(NSString *)name age:(NSNumber *)age completion:(void(^)(BOOL success, NSError *error))completion;
  8. - (void)fetchAllPersons:(void(^)(NSArray *persons, NSError *error))completion;
  9. @end
  10. @implementation CoreDataManager
  11. + (instancetype)sharedManager {
  12. static CoreDataManager *sharedManager = nil;
  13. static dispatch_once_t onceToken;
  14. dispatch_once(&onceToken, ^{
  15. sharedManager = [[self alloc] init];
  16. });
  17. return sharedManager;
  18. }
  19. - (NSPersistentContainer *)persistentContainer {
  20. @synchronized (self) {
  21. if (_persistentContainer == nil) {
  22. _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"YourModelName"];
  23. [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
  24. if (error != nil) {
  25. NSLog(@"Unresolved error %@, %@", error, error.userInfo);
  26. abort();
  27. }
  28. }];
  29. }
  30. }
  31. return _persistentContainer;
  32. }
  33. - (void)saveContext {
  34. NSManagedObjectContext *context = self.persistentContainer.viewContext;
  35. NSError *error = nil;
  36. if ([context hasChanges] && ![context save:&error]) {
  37. NSLog(@"Unresolved error %@, %@", error, error.userInfo);
  38. abort();
  39. }
  40. }
  41. - (void)insertPersonWithName:(NSString *)name age:(NSNumber *)age completion:(void(^)(BOOL success, NSError *error))completion {
  42. NSManagedObjectContext *context = self.persistentContainer.viewContext;
  43. NSManagedObject *newPerson = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
  44. [newPerson setValue:name forKey:@"name"];
  45. [newPerson setValue:age forKey:@"age"];
  46. NSError *error = nil;
  47. if (![context save:&error]) {
  48. NSLog(@"Error saving context: %@, %@", error, error.userInfo);
  49. completion(NO, error);
  50. } else {
  51. completion(YES, nil);
  52. }
  53. }
  54. - (void)fetchAllPersons:(void(^)(NSArray *persons, NSError *error))completion {
  55. NSManagedObjectContext *context = self.persistentContainer.viewContext;
  56. NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
  57. NSError *error = nil;
  58. NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
  59. if (error) {
  60. NSLog(@"Failed to fetch persons: %@, %@", error, error.userInfo);
  61. completion(nil, error);
  62. } else {
  63. completion(results, nil);
  64. }
  65. }
  66. @end

使用封装的CoreDataManager

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

  1. // 插入新的Person对象
  2. [[CoreDataManager sharedManager] insertPersonWithName:@"John Doe" age:@25 completion:^(BOOL success, NSError *error) {
  3. if (success) {
  4. NSLog(@"Person added successfully");
  5. } else {
  6. NSLog(@"Failed to add person: %@", error.localizedDescription);
  7. }
  8. }];
  9. // 获取所有的Person对象
  10. [[CoreDataManager sharedManager] fetchAllPersons:^(NSArray * _Nonnull persons, NSError * _Nonnull error) {
  11. if (error) {
  12. NSLog(@"Failed to fetch persons: %@", error.localizedDescription);
  13. } else {
  14. for (NSManagedObject *person in persons) {
  15. NSString *name = [person valueForKey:@"name"];
  16. NSNumber *age = [person valueForKey:@"age"];
  17. NSLog(@"Fetched person: %@, age: %@", name, age);
  18. }
  19. }
  20. }];

通过上面的封装,我们只需调用简单的方法就可以完成对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. AI实战 | 手把手带你打造校园生活助手

    大家好,我是努力的小雨.最近,我开始将我的经验逐渐分享到B站,希望能够帮助大家通过扣子助手真正解决一些问题.最近有粉丝提出了一个需求,为了满足大家的期待,我已经制作了视频,详细介绍了这个助手的搭建思路 ...

  2. Vue 组件生命周期:探索钩子

    title: Vue 组件生命周期:探索钩子 date: 2024/5/27 18:42:38 updated: 2024/5/27 18:42:38 categories: 前端开发 tags: 生 ...

  3. 个人记录:连接、查询、写入PG数据库类文件

    # --coding:utf-8-- import pandas as pd import yaml from sqlalchemy import create_engine import psyco ...

  4. 基于centos7的企业级ceph集群搭建[nautilus14.22版]

    集群规划 本案例通过ceph-deploy方式部署 主机名 配置 外网IP / 内网IP 角色 系统版本 ceph-node01 磁盘x3 50G 192.168.3.101/24 172.16.1. ...

  5. ra6m3之adc踩坑日志(基于rt-thread )

    问题描述 1.已经用fsp工具正确配置Pins 2.已经用fsp工具正确配置Stacks 3.问题是根本没有在RT-Thread Studio看到HAL相关的ADC代码,也没看到Settings里边的 ...

  6. Yolov8和Yolov10的差异以及后处理实现

    Yolo模型可分为4个维度的概念 模型版本.数据集.模型变体(Variants).动态/静态模型. Yolo各模型版本进展历史 Yolov(2015年华盛顿大学的 Joseph Redmon 和 Al ...

  7. 剑指Offer-55.链表中环的入口结点(C++/Java)

    题目: 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null. 分析: 利用快慢指针,如果链表中存在环的话,则快指针一定在环中的某个节点与慢指针相遇. 设头节点到链表的环的入口结点 ...

  8. Grafana 开源了一款 eBPF 采集器 Beyla

    eBPF 的发展如火如荼,在可观测性领域大放异彩,Grafana 近期也发布了一款 eBPF 采集器,可以采集服务的 RED 指标,本文做一个尝鲜介绍,让读者有个大概了解. eBPF 基础介绍可以参考 ...

  9. 泛型模板化设计DEMO

    泛型模板化设计DEMO 1. 定义Result泛型类 package com.example.core.mydemo.java.fanxing; public class Result<T> ...

  10. Nginx SSL证书更新及密码套件更新

    一.域名更换证书 ssl证书一般包括证书文件crt.cer.pem.pfx和私钥文件key. CER.CRT.PEM 和 PFX 是不同的证书文件格式,它们之间存在一些区别: CER (DER 编码) ...