Swift Core Data 框架(20)

一、Swift Core Data 框架概述

Swift Core Data 是 Apple 平台上的一个强大的数据持久化框架,它提供了对象-关系映射(ORM)功能,允许开发者以面向对象的方式管理和存储数据。Core Data 不仅支持将数据存储到本地磁盘,还提供了对象图管理、数据验证、撤销/重做等高级功能。

Core Data 的核心组件包括:

  1. NSManagedObjectModel:表示应用的数据模型,包含实体(Entity)、属性(Attribute)和关系(Relationship)的定义。

  2. NSPersistentStoreCoordinator:负责管理数据的存储和读取,处理不同类型的持久化存储(如 SQLite、XML、二进制文件等)。

  3. NSManagedObjectContext:提供了一个工作空间,用于创建、读取、更新和删除托管对象。它跟踪对象的变化,并在需要时将这些变化保存到持久化存储中。

  4. NSManagedObject:表示模型中的实体实例,是应用直接操作的数据对象。

Core Data 的工作流程通常包括以下步骤:

  1. 创建或加载托管对象模型。

  2. 创建持久化存储协调器并添加持久化存储。

  3. 创建托管对象上下文并将其与持久化存储协调器关联。

  4. 使用托管对象上下文执行数据操作(创建、读取、更新、删除)。

  5. 当需要保存更改时,调用托管对象上下文的 save() 方法。

下面我们将深入分析 Core Data 各组件的源码实现。

二、Core Data 核心组件源码分析

2.1 托管对象模型(NSManagedObjectModel)

托管对象模型是 Core Data 的数据蓝图,它定义了应用的数据结构。在源码中,NSManagedObjectModel 类的核心实现如下:

@interface NSManagedObjectModel : NSObject 

// 初始化方法,从URL加载模型
- (instancetype)initWithContentsOfURL:(NSURL *)modelURL;

// 获取模型中的所有实体
@property (readonly, copy) NSArray *entities;

// 根据名称获取实体
- (NSEntityDescription *)entityForName:(NSString *)entityName;

// 模型的版本信息
@property (readonly, copy) NSString *versionHashModifier;
@property (readonly, copy) NSDictionary *versionHashesByName;

@end

NSManagedObjectModel 的实现涉及以下几个关键部分:

  1. 实体管理:模型内部维护一个实体数组,每个实体由 NSEntityDescription 表示。

  2. 版本控制:Core Data 支持模型版本控制,通过 versionHashesByName 属性可以获取每个实体的版本哈希值。

  3. 加载机制:模型可以从 .momd.mom 文件加载,这些文件是 Xcode 编译数据模型文件(.xcdatamodeld)后生成的。

NSEntityDescription 类表示模型中的实体,其核心实现如下:

@interface NSEntityDescription : NSObject 

// 实体名称
@property (nullable, copy) NSString *name;

// 实体的父实体(用于继承)
@property (nullable, strong) NSEntityDescription *superentity;

// 实体的属性和关系
@property (readonly, copy) NSArray *attributes;
@property (readonly, copy) NSArray *relationships;

// 实体对应的类名
@property (nullable, copy) NSString *managedObjectClassName;

// 创建实体的实例
- (NSManagedObject *)insertNewObjectIntoContext:(NSManagedObjectContext *)context;

@end

NSEntityDescription 负责定义实体的属性、关系和继承结构。每个实体可以有一个父实体,形成继承层次结构。

2.2 持久化存储协调器(NSPersistentStoreCoordinator)

持久化存储协调器是 Core Data 的数据存储管理器,它的核心实现如下:

@interface NSPersistentStoreCoordinator : NSObject 

// 初始化方法,传入托管对象模型
- (instancetype)initWithManagedObjectModel:(NSManagedObjectModel *)model;

// 托管对象模型
@property (readonly, strong) NSManagedObjectModel *managedObjectModel;

// 添加持久化存储
- (NSPersistentStore *)addPersistentStoreWithType:(NSString *)storeType
                                          configuration:(nullable NSString *)configuration
                                                    URL:(nullable NSURL *)storeURL
                                                options:(nullable NSDictionary *)options
                                                  error:(NSError **)error;

// 移除持久化存储
- (BOOL)removePersistentStore:(NSPersistentStore *)store error:(NSError **)error;

// 获取所有持久化存储
@property (readonly, copy) NSArray *persistentStores;

@end

NSPersistentStoreCoordinator 的实现涉及以下几个关键部分:

  1. 存储类型支持:Core Data 支持多种存储类型,包括 SQLite(NSSQLiteStoreType)、XML(NSXMLStoreType)、二进制(NSBinaryStoreType)和内存(NSInMemoryStoreType)。

  2. 存储管理:协调器维护一个持久化存储数组,每个存储由 NSPersistentStore 表示。

  3. 存储加载addPersistentStoreWithType: 方法负责加载指定类型的存储,并将其与协调器关联。

NSPersistentStore 类是一个抽象基类,具体的存储类型由其子类实现。例如,SQLite 存储由 NSSQLCore 类实现,它继承自 NSPersistentStore

2.3 托管对象上下文(NSManagedObjectContext)

托管对象上下文是 Core Data 的工作horse,它的核心实现如下:

@interface NSManagedObjectContext : NSObject 

// 初始化方法
- (instancetype)init;
- (instancetype)initWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType;

// 并发类型
@property (readonly) NSManagedObjectContextConcurrencyType concurrencyType;

// 持久化存储协调器
@property (nullable, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;

// 父上下文(用于父子上下文架构)
@property (nullable, strong) NSManagedObjectContext *parentContext;

// 插入新对象
- (void)insertObject:(NSManagedObject *)object;

// 获取对象
- (nullable NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID;
- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error;

// 删除对象
- (void)deleteObject:(NSManagedObject *)object;

// 保存更改
- (BOOL)save:(NSError **)error;

// 撤销/重做支持
@property (nullable, strong) NSUndoManager *undoManager;
- (void)undo;
- (void)redo;

// 注册通知
@property (class, readonly, copy) NSString *NSManagedObjectContextDidSaveNotification;
@property (class, readonly, copy) NSString *NSManagedObjectContextObjectsDidChangeNotification;

@end

NSManagedObjectContext 的实现涉及以下几个关键部分:

  1. 对象注册与跟踪:上下文维护一个注册表,记录所有被管理的对象及其状态(如新插入、已修改、已删除)。

  2. 变化管理:上下文跟踪对象的变化,并在调用 save() 方法时将这些变化持久化到存储中。

  3. 并发支持:上下文支持不同的并发类型(主队列、私有队列),通过 performBlock:performBlockAndWait: 方法确保线程安全。

  4. 父子上下文架构:上下文可以有父子关系,形成层次结构,子上下文的变化可以逐级提交到父上下文,最终保存到持久化存储。

2.4 托管对象(NSManagedObject)

托管对象是 Core Data 中的数据对象,它的核心实现如下:

@interface NSManagedObject : NSObject 

// 初始化方法
- (instancetype)initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(nullable NSManagedObjectContext *)context;

// 实体描述
@property (readonly, strong) NSEntityDescription *entity;

// 托管对象上下文
@property (nullable, readonly, strong) NSManagedObjectContext *managedObjectContext;

// 对象ID
@property (readonly, strong) NSManagedObjectID *objectID;

// 对象状态
@property (readonly) NSManagedObjectState managedObjectState;

// 属性访问
- (id)valueForKey:(NSString *)key;
- (void)setValue:(id)value forKey:(NSString *)key;

// 验证方法
- (BOOL)validateForInsert:(NSError **)error;
- (BOOL)validateForUpdate:(NSError **)error;
- (BOOL)validateForDelete:(NSError **)error;

@end

NSManagedObject 的实现涉及以下几个关键部分:

  1. 动态属性访问:通过 valueForKey:setValue:forKey: 方法实现动态属性访问,这些方法会根据实体描述动态查找和设置属性值。

  2. 对象状态管理:每个对象有一个状态(如 NSManagedObjectStateInsertedNSManagedObjectStateUpdatedNSManagedObjectStateDeleted),上下文通过这些状态来跟踪对象的变化。

  3. 验证机制:提供验证方法,确保对象在插入、更新或删除前满足实体定义的约束条件。

三、Core Data 的数据存储机制

3.1 SQLite 存储实现

Core Data 默认使用 SQLite 作为持久化存储,其实现涉及以下关键部分:

  1. SQLite 包装层:Core Data 提供了一个 SQLite 包装层,处理与 SQLite 数据库的底层交互。这个包装层隐藏了 SQLite 的 C API 细节,提供了更高级的抽象。
// NSSQLCore 类的部分实现,负责 SQLite 存储
@interface NSSQLCore : NSPersistentStore {
    // SQLite 数据库连接
    sqlite3 *_db;
    
    // 缓存的 SQL 语句
    NSMutableDictionary *_sqlCache;
    
    // 数据库架构信息
    NSSQLModel *_model;
    
    // 其他成员变量...
}

// 打开数据库
- (BOOL)_openDatabase:(NSError **)error;

// 执行 SQL 语句
- (BOOL)_executeSQL:(NSString *)sql error:(NSError **)error;

// 执行查询并返回结果集
- (NSSQLRowCache *)_newRowsForFetchPlan:(NSSQLFetchRequestContext *)fetchPlan error:(NSError **)error;

@end
  1. 模式映射:Core Data 将托管对象模型映射到 SQLite 数据库模式。每个实体对应一个表,每个属性对应表中的一列。
// NSSQLModel 类的部分实现,负责模型到 SQL 的映射
@interface NSSQLModel : NSObject {
    // 实体到表的映射
    NSMutableDictionary *_entitiesByName;
    
    // 其他成员变量...
}

// 根据实体获取对应的表描述
- (NSSQLEntity *)entityForDescription:(NSEntityDescription *)entityDescription;

// 生成创建表的 SQL 语句
- (NSString *)_createTableStatementForEntity:(NSSQLEntity *)entity;

@end
  1. SQL 生成:Core Data 根据操作生成相应的 SQL 语句,如插入、查询、更新、删除等。
// NSSQLGenerator 类的部分实现,负责生成 SQL 语句
@interface NSSQLGenerator : NSObject {
    // 当前生成的 SQL 语句
    NSMutableString *_sqlString;
    
    // 其他成员变量...
}

// 生成插入语句
- (NSString *)generateInsertStatementForRow:(NSSQLRow *)row;

// 生成查询语句
- (NSString *)generateSelectStatementForFetchRequest:(NSFetchRequest *)request;

// 生成更新语句
- (NSString *)generateUpdateStatementForRow:(NSSQLRow *)row withOriginalRow:(NSSQLRow *)originalRow;

// 生成删除语句
- (NSString *)generateDeleteStatementForRow:(NSSQLRow *)row;

@end
3.2 其他存储类型实现

除了 SQLite,Core Data 还支持其他存储类型:

  1. XML 存储:将数据以 XML 格式存储,适合小型数据和调试。

  2. 二进制存储:将数据以二进制格式存储,读写效率较高。

  3. 内存存储:将数据存储在内存中,适合临时数据和测试。

这些存储类型的实现与 SQLite 存储类似,但在数据格式和读写方式上有所不同。

3.3 存储迁移机制

当数据模型发生变化时,Core Data 提供了迁移机制。迁移过程涉及源模型、目标模型和映射模型。

// NSMappingModel 类的部分实现,负责模型迁移映射
@interface NSMappingModel : NSObject  {
    // 源模型和目标模型
    NSManagedObjectModel *_sourceModel;
    NSManagedObjectModel *_destinationModel;
    
    // 实体映射
    NSArray *_entityMappings;
    
    // 其他成员变量...
}

// 创建映射模型
+ (nullable instancetype)mappingModelFromBundles:(nullable NSArray *)bundles forSourceModel:(NSManagedObjectModel *)sourceModel destinationModel:(NSManagedObjectModel *)destinationModel;

// 执行迁移
- (BOOL)migrateStoreFromURL:(NSURL *)sourceURL
                      type:(NSString *)sourceStoreType
                   options:(nullable NSDictionary *)sourceOptions
          withMappingModel:(nullable NSMappingModel *)mappingModel
          toDestinationURL:(NSURL *)destinationURL
           destinationType:(NSString *)destinationStoreType
        destinationOptions:(nullable NSDictionary *)destinationOptions
                      error:(NSError **)error;

@end

轻量级迁移是 Core Data 提供的一种自动迁移机制,适用于简单的模型变化:

// 轻量级迁移选项
NSDictionary *options = @{
    NSMigratePersistentStoresAutomaticallyOption: @YES,
    NSInferMappingModelAutomaticallyOption: @YES
};

// 添加持久化存储时使用这些选项
NSError *error = nil;
NSPersistentStore *store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                          configuration:nil
                                                                    URL:storeURL
                                                                options:options
                                                                  error:&error];

四、Core Data 的查询机制

4.1 NSFetchRequest 实现

NSFetchRequest 是 Core Data 中用于查询数据的核心类,其实现涉及以下关键部分:

@interface NSFetchRequest : NSObject 

// 初始化方法
+ (instancetype)fetchRequestWithEntityName:(NSString *)entityName;

// 查询的实体
@property (nullable, strong) NSEntityDescription *entity;

// 查询谓词
@property (nullable, strong) NSPredicate *predicate;

// 排序描述符
@property (nullable, copy) NSArray *sortDescriptors;

// 结果限制
@property NSInteger fetchLimit;
@property NSInteger fetchOffset;

// 返回类型
@property NSFetchRequestResultType resultType;

// 执行查询
- (NSArray *)execute:(NSError **)error;

@end

NSFetchRequest 的实现涉及查询条件的构建、排序和分页的处理,以及查询结果的返回类型控制。

4.2 谓词(NSPredicate)实现

谓词是 Core Data 中用于定义查询条件的机制,其实现涉及多种谓词类型:

@interface NSPredicate : NSObject 

// 创建谓词的工厂方法
+ (instancetype)predicateWithFormat:(NSString *)predicateFormat, ...;
+ (instancetype)predicateWithFormat:(NSString *)predicateFormat arguments:(va_list)argList;
+ (instancetype)predicateWithValue:(BOOL)value;

// 评估谓词
- (BOOL)evaluateWithObject:(id)object;

// 子类需要实现的方法
- (void)acceptVisitor:(id)visitor flags:(NSUInteger)flags;

@end

// 比较谓词
@interface NSComparisonPredicate : NSPredicate {
    // 左侧表达式
    NSExpression *_leftExpression;
    
    // 右侧表达式
    NSExpression *_rightExpression;
    
    // 比较操作符
    NSPredicateOperatorType _comparisonPredicateOperatorType;
    
    // 其他成员变量...
}

@end

// 逻辑谓词
@interface NSCompoundPredicate : NSPredicate {
    // 子谓词
    NSArray *_subpredicates;
    
    // 逻辑操作符(AND、OR、NOT)
    NSCompoundPredicateType _compoundPredicateType;
    
    // 其他成员变量...
}

@end

谓词的实现涉及表达式解析、逻辑运算和比较操作的处理。Core Data 使用谓词来过滤查询结果,确保只返回符合条件的数据。

4.3 查询执行流程

Core Data 查询的执行流程涉及以下关键步骤:

  1. 请求验证:验证查询请求的有效性,确保实体、谓词等设置正确。

  2. 查询计划生成:根据查询请求和存储类型生成最优的查询计划。

  3. SQL 生成:将查询请求转换为具体的 SQL 语句(对于 SQLite 存储)。

  4. 数据检索:执行 SQL 语句,从数据库中检索数据。

  5. 对象创建与缓存:根据检索到的数据创建托管对象,并进行缓存。

下面是查询执行的部分源码实现:

// NSManagedObjectContext 中执行查询的方法
- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error {
    // 验证请求
    if (![self _validateFetchRequest:request error:error]) {
        return nil;
    }
    
    // 创建查询上下文
    NSFetchRequestContext *fetchContext = [[NSFetchRequestContext alloc] initWithFetchRequest:request context:self];
    
    // 执行查询计划
    id result = [self.persistentStoreCoordinator executeRequest:request withContext:self error:error];
    
    if (result == nil) {
        return nil;
    }
    
    // 处理查询结果
    return [self _processFetchResult:result forRequest:request context:fetchContext error:error];
}

// NSPersistentStoreCoordinator 中执行查询的方法
- (id)executeRequest:(NSPersistentStoreRequest *)request withContext:(NSManagedObjectContext *)context error:(NSError **)error {
    // 根据请求类型选择合适的存储执行请求
    if ([request isKindOfClass:[NSFetchRequest class]]) {
        NSFetchRequest *fetchRequest = (NSFetchRequest *)request;
        
        // 确定使用哪个存储执行查询
        NSPersistentStore *store = [self _storeForEntity:fetchRequest.entity];
        
        if (!store) {
            if (error) *error = [NSError errorWithDomain:NSPersistentStoreCoordinatorErrorDomain code:NSPersistentStoreIncompatibleVersionHashError userInfo:nil];
            return nil;
        }
        
        // 在存储上执行查询
        return [store executeRequest:request withContext:context error:error];
    }
    
    // 处理其他类型的请求...
    
    return nil;
}

// NSSQLCore(SQLite 存储)中执行查询的方法
- (id)executeRequest:(NSPersistentStoreRequest *)request withContext:(NSManagedObjectContext *)context error:(NSError **)error {
    if ([request isKindOfClass:[NSFetchRequest class]]) {
        NSFetchRequest *fetchRequest = (NSFetchRequest *)request;
        
        // 生成 SQL 查询语句
        NSString *sql = [self _generateSQLForFetchRequest:fetchRequest];
        
        // 执行 SQL 查询
        sqlite3_stmt *stmt;
        int result = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &stmt, NULL);
        
        if (result != SQLITE_OK) {
            if (error) *error = [NSError errorWithDomain:NSSQLiteErrorDomain code:result userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"SQLite error: %s", sqlite3_errmsg(_db)]}];
            return nil;
        }
        
        // 处理查询结果
        NSMutableArray *results = [NSMutableArray array];
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            // 从结果集中提取数据
            id object = [self _objectFromResultSet:stmt forEntity:fetchRequest.entity];
            
            // 如果对象已存在于上下文中,则使用上下文中的实例
            if ([context registeredObjectForID:[object objectID]]) {
                object = [context objectWithID:[object objectID]];
            } else {
                // 注册新对象
                [context _registerObject:object];
            }
            
            [results addObject:object];
        }
        
        sqlite3_finalize(stmt);
        
        return results;
    }
    
    // 处理其他类型的请求...
    
    return nil;
}

五、Core Data 的变化跟踪与保存机制

5.1 变化跟踪机制

Core Data 的变化跟踪机制涉及以下关键部分:

  1. 对象状态管理:每个托管对象有一个状态,定义在 NSManagedObject.h 中:
typedef NS_ENUM(NSUInteger, NSManagedObjectState) {
    NSManagedObjectStateTransient,    // 临时状态,刚创建但未插入上下文
    NSManagedObjectStatePending,      // 已插入上下文但未保存
    NSManagedObjectStateInserted,     // 已插入且未保存
    NSManagedObjectStateUpdated,      // 已修改且未保存
    NSManagedObjectStateDeleted,      // 已删除且未保存
    NSManagedObjectStateRefreshed,    // 已刷新
    NSManagedObjectStateFault         // 未加载(故障状态)
};
  1. 变化记录:上下文维护一个变化记录,记录所有被修改的对象:
// NSManagedObjectContext 中变化跟踪的部分实现
@interface NSManagedObjectContext () {
    // 已插入的对象集合
    NSMutableSet *_insertedObjects;
    
    // 已修改的对象集合
    NSMutableSet *_updatedObjects;
    
    // 已删除的对象集合
    NSMutableSet *_deletedObjects;
    
    // 其他成员变量...
}

// 注册对象的插入
- (void)_registerInsertedObject:(NSManagedObject *)object;

// 注册对象的修改
- (void)_registerUpdatedObject:(NSManagedObject *)object;

// 注册对象的删除
- (void)_registerDeletedObject:(NSManagedObject *)object;

// 检查对象是否有未保存的变化
- (BOOL)_objectHasChanges:(NSManagedObject *)object;

@end
  1. 撤销管理器集成:上下文可以与 NSUndoManager 集成,支持撤销和重做操作:
// NSManagedObjectContext 中撤销支持的部分实现
- (void)undo {
    if (self.undoManager && [self.undoManager canUndo]) {
        [self.undoManager undo];
    }
}

- (void)redo {
    if (self.undoManager && [self.undoManager canRedo]) {
        [self.undoManager redo];
    }
}

// 注册撤销操作
- (void)_registerUndoForOperation:(NSString *)operation withTarget:(id)target selector:(SEL)selector object:(id)object {
    if (self.undoManager) {
        [self.undoManager registerUndoWithTarget:target selector:selector object:object];
        [self.undoManager setActionName:operation];
    }
}
5.2 保存操作实现

保存操作将上下文的变化持久化到存储中,其实现涉及以下关键部分:

// NSManagedObjectContext 中 save 方法的部分实现
- (BOOL)save:(NSError **)error {
    // 检查是否有变化需要保存
    if (![self hasChanges]) {
        return YES;
    }
    
    // 验证所有变化的对象
    if (![self _validateChangesForSave:error]) {
        return NO;
    }
    
    // 开始事务
    if (![self _beginTransaction:error]) {
        return NO;
    }
    
    BOOL success = NO;
    
    @try {
        // 保存变化到持久化存储
        if ([self.parentContext]) {
            // 如果有父上下文,先将变化保存到父上下文
            [self.parentContext performBlockAndWait:^{
                success = [self.parentContext save:error];
            }];
        } else {
            // 没有父上下文,直接保存到持久化存储
            success = [self.persistentStoreCoordinator saveChanges:self error:error];
        }
        
        if (success) {
            // 保存成功,清除变化记录
            [self _clearChanges];
            
            // 发送保存通知
            [self _postSaveNotification];
        }
    }
    @catch (NSException *exception) {
        // 处理异常
        if (error) {
            *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSManagedObjectContextSaveException userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Save failed: %@", [exception reason]]}];
        }
        success = NO;
    }
    @finally {
        // 结束事务
        [self _endTransaction];
    }
    
    return success;
}

// NSPersistentStoreCoordinator 中保存变化的方法
- (BOOL)saveChanges:(NSManagedObjectContext *)context error:(NSError **)error {
    // 获取上下文中的变化
    NSSet *insertedObjects = [context insertedObjects];
    NSSet *updatedObjects = [context updatedObjects];
    NSSet *deletedObjects = [context deletedObjects];
    
    // 对每个存储执行保存操作
    for (NSPersistentStore *store in self.persistentStores) {
        // 筛选出属于该存储的对象
        NSSet *storeInsertedObjects = [self _objectsInSet:insertedObjects forStore:store];
        NSSet *storeUpdatedObjects = [self _objectsInSet:updatedObjects forStore:store];
        NSSet *storeDeletedObjects = [self _objectsInSet:deletedObjects forStore:store];
        
        // 在存储上执行保存
        if (![store saveChangesToStore:storeInsertedObjects updatedObjects:storeUpdatedObjects deletedObjects:storeDeletedObjects withContext:context error:error]) {
            return NO;
        }
    }
    
    return YES;
}

// NSSQLCore(SQLite 存储)中保存变化的方法
- (BOOL)saveChangesToStore:(NSSet *)insertedObjects updatedObjects:(NSSet *)updatedObjects deletedObjects:(NSSet *)deletedObjects withContext:(NSManagedObjectContext *)context error:(NSError **)error {
    // 开始 SQLite 事务
    if (![self _beginSQLTransaction:error]) {
        return NO;
    }
    
    BOOL success = YES;
    
    @try {
        // 处理删除的对象
        for (NSManagedObject *object in deletedObjects) {
            if (![self _deleteObject:object error:error]) {
                success = NO;
                break;
            }
        }
        
        // 处理更新的对象
        if (success) {
            for (NSManagedObject *object in updatedObjects) {
                if (![self _updateObject:object error:error]) {
                    success = NO;
                    break;
                }
            }
        }
        
        // 处理插入的对象
        if (success) {
            for (NSManagedObject *object in insertedObjects) {
                if (![self _insertObject:object error:error]) {
                    success = NO;
                    break;
                }
            }
        }
        
        // 提交事务
        if (success) {
            if (![self _commitSQLTransaction:error]) {
                success = NO;
            }
        } else {
            // 回滚事务
            [self _rollbackSQLTransaction];
        }
    }
    @catch (NSException *exception) {
        // 处理异常
        if (error) {
            *error = [NSError errorWithDomain:NSSQLiteErrorDomain code:NSInternalInconsistencyException userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Save failed: %@", [exception reason]]}];
        }
        success = NO;
        [self _rollbackSQLTransaction];
    }
    
    return success;
}
5.3 冲突解决机制

当多个上下文同时修改同一数据时,可能会发生冲突,Core Data 提供了冲突解决机制:

// NSManagedObjectContext 中冲突解决的部分实现
- (BOOL)_resolveConflicts:(NSArray *)conflicts error:(NSError **)error {
    // 如果没有设置冲突解决策略,使用默认策略
    NSMergePolicyType mergePolicyType = self.mergePolicy.mergeType;
    
    for (NSMergeConflict *conflict in conflicts) {
        BOOL resolved = NO;
        
        switch (mergePolicyType) {
            case NSMergeByPropertyStoreTrumpMergePolicyType:
                // 属性存储胜出策略:使用存储中的值覆盖内存中的值
                resolved = [self _resolveConflict:conflict usingStoreTrumpPolicy];
                break;
                
            case NSMergeByPropertyObjectTrumpMergePolicyType:
                // 属性对象胜出策略:使用内存中的值覆盖存储中的值
                resolved = [self _resolveConflict:conflict usingObjectTrumpPolicy];
                break;
                
            case NSOverwriteMergePolicyType:
                // 覆盖策略:直接用当前上下文的值覆盖存储中的值
                resolved = [self _resolveConflict:conflict usingOverwritePolicy];
                break;
                
            case ABORT:
                // 中止策略:不解决冲突,抛出错误
                if (error) {
                    *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSManagedObjectContextMergeConflictError userInfo:@{NSMergeConflictsKey: @[conflict]}];
                }
                return NO;
                
            default:
                // 自定义策略
                resolved = [self.mergePolicy resolveConflict:conflict error:error];
                break;
        }
        
        if (!resolved) {
            if (error) {
                *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSManagedObjectContextMergeConflictError userInfo:@{NSMergeConflictsKey: @[conflict]}];
            }
            return NO;
        }
    }
    
    return YES;
}

六、Core Data 的线程安全机制

6.1 上下文的线程限制

Core Data 的上下文不是线程安全的,其源码实现中涉及以下线程安全机制:

// NSManagedObjectContext 中并发控制的部分实现
@interface NSManagedObjectContext () {
    // 并发队列
    dispatch_queue_t _queue;
    
    // 并发类型
    NSManagedObjectContextConcurrencyType _concurrencyType;
    
    // 其他成员变量...
}

// 在上下文的队列上执行块
- (void)performBlock:(void (^)(void))block;
- (void)performBlockAndWait:(void (^)(void))block;

// 验证当前是否在正确的线程/队列上执行
- (BOOL)_isValidThreadForOperation;
- (void)_enforceReadOnly;
- (void)_enforceReadWrite;

@end

// performBlock 方法的实现
- (void)performBlock:(void (^)(void))block {
    if (!block) return;
    
    if (_concurrencyType == NSMainQueueConcurrencyType) {
        dispatch_async(dispatch_get_main_queue(), block);
    } else {
        dispatch_async(_queue, block);
    }
}

// performBlockAndWait 方法的实现
- (void)performBlockAndWait:(void (^)(void))block {
    if (!block) return;
    
    if (_concurrencyType == NSMainQueueConcurrencyType) {
        if ([NSThread isMainThread]) {
            block();
        } else {
            dispatch_sync(dispatch_get_main_queue(), block);
        }
    } else {
        dispatch_sync(_queue, block);
    }
}
6.2 多上下文架构

为了在多线程环境中使用 Core Data,通常采用多上下文架构:

// 创建父子上下文架构的示例代码
- (void)setupCoreDataStack {
    // 创建主上下文,与主线程关联
    _mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    _mainContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
    
    // 创建私有上下文,用于后台操作
    _privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    _privateContext.parentContext = _mainContext;
    
    // 监听保存通知,确保上下文之间的数据同步
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(contextDidSave:)
                                                 name:NSManagedObjectContextDidSaveNotification
                                               object:_privateContext];
}

// 处理保存通知的方法
- (void)contextDidSave:(NSNotification *)notification {
    // 确保在主上下文的队列上执行
    [_mainContext performBlock:^{
        // 合并变化
        [_mainContext mergeChangesFromContextDidSaveNotification:notification];
        
        // 保存主上下文到持久化存储
        NSError *error = nil;
        if (![_mainContext save:&error]) {
            NSLog(@"Error saving main context: %@", error);
        }
    }];
}
6.3 跨线程通信机制

Core Data 提供了多种跨线程通信机制:

  1. 使用 performBlock 和 performBlockAndWait

    • 确保所有对上下文的操作都在上下文的队列上执行。
  2. 使用对象 ID

    • 通过 objectID 在不同上下文之间引用同一对象:
// 在后台线程获取对象 ID
NSManagedObjectID *objectID = [managedObject objectID];

// 在主线程通过对象 ID 获取对象
[_mainContext performBlock:^{
    NSManagedObject *object = [_mainContext objectWithID:objectID];
    // 使用对象...
}];
  1. 通知机制
    • 使用 NSManagedObjectContextDidSaveNotification 通知其他上下文有变化发生:
// 注册通知
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(contextDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:nil];

// 处理通知
- (void)contextDidSave:(NSNotification *)notification {
    // 合并变化
    [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}

七、Core Data 的缓存机制

7.1 对象缓存

Core Data 实现了对象缓存机制,确保同一对象在同一上下文中只有一个实例:

// NSManagedObjectContext 中对象缓存的部分实现
@interface NSManagedObjectContext () {
    // 对象缓存
    NSMutableDictionary *_objectCache;
    
    // 对象 ID 到对象的映射
    NSMutableDictionary *_objectIDsToObjects;
    
    // 其他成员变量...
}

// 注册对象到缓存
- (void)_registerObject:(NSManagedObject *)object;

// 从缓存中获取对象
- (nullable NSManagedObject *)_objectForID:(NSManagedObjectID *)objectID;

// 从缓存中移除对象
- (void)_unregisterObject:(NSManagedObject *)object;

@end

// 注册对象到缓存的方法
- (void)_registerObject:(NSManagedObject *)object {
    @synchronized(self) {
        // 将对象添加到缓存
        [_objectCache setObject:object forKey:[object objectID]];
        
        // 如果对象是新插入的,记录其初始值
        if (object.managedObjectState == NSManagedObjectStateInserted) {
            [self _recordInitialValuesForObject:object];
        }
    }
}

// 从缓存中获取对象的方法
- (nullable NSManagedObject *)_objectForID:(NSManagedObjectID *)objectID {
    @synchronized(self) {
        return [_objectCache objectForKey:objectID];
    }
}
7.2 元数据缓存

Core Data 还实现了元数据缓存机制,提高模型加载和查询效率:

// NSManagedObjectModel 中缓存的部分实现
@interface NSManagedObjectModel () {
    // 实体名称到实体的映射
    NSMutableDictionary *_entitiesByName;
    
    // 版本哈希缓存
    NSMutableDictionary *_versionHashesByName;
    
    // 其他成员变量...
}

// 从缓存中获取实体
- (nullable NSEntityDescription *)_entityByName:(NSString *)name;

// 计算并缓存版本哈希
- (NSData *)_versionHashForEntity:(NSEntityDescription *)entity;

@end

// NSPersistentStoreCoordinator 中缓存的部分实现
@interface NSPersistentStoreCoordinator () {
    // 存储类型到存储类的映射
    NSMutableDictionary *_storeTypeToClassMap;
    
    // 存储 URL 到存储的映射
    NSMutableDictionary *_storeURLToStoreMap;
    
    // 其他成员变量...
}

// 从缓存中获取存储类
- (Class)_storeClassForType:(NSString *)storeType;

// 从缓存中获取存储
- (nullable NSPersistentStore *)_storeForURL:(NSURL *)storeURL;

@end
7.3 缓存淘汰策略

当内存不足时,Core Data 会执行缓存淘汰策略:

// NSManagedObjectContext 中缓存淘汰的部分实现
- (void)_evictObjectsIfNeeded {
    // 检查内存使用情况
    BOOL memoryPressure = [self _hasMemoryPressure];
    
    if (memoryPressure) {
        // 获取可以安全释放的对象
        NSArray *objectsToEvict = [self _objectsToEvict];
        
        // 释放对象
        for (NSManagedObject *object in objectsToEvict) {
            [self _evictObject:object];
        }
    }
}

// 获取可以安全释放的对象
- (NSArray *)_objectsToEvict {
    NSMutableArray *objects = [NSMutableArray array];
    
    // 遍历缓存中的对象
    for (NSManagedObject *object in [_objectCache allValues]) {
        // 只释放未被修改且未被引用的对象
        if (object.managedObjectState == NSManagedObjectStateUnchanged && 
            [object _referenceCount] == 1) {
            [objects addObject:object];
        }
    }
    
    // 根据访问时间排序,先释放最久未使用的对象
    [objects sortUsingComparator:^NSComparisonResult(NSManagedObject *obj1, NSManagedObject *obj2) {
        return [obj1 _lastAccessTime] compare:[obj2 _lastAccessTime];
    }];
    
    // 只返回一部分对象,避免释放过多
    NSUInteger countToEvict = MIN(objects.count, [self _maxObjectsToEvict]);
    return [objects subarrayWithRange:NSMakeRange(0, countToEvict)];
}

// 释放对象
- (void)_evictObject:(NSManagedObject *)object {
    // 将对象转换为故障状态
    [object _turnIntoFault];
    
    // 从缓存中移除
    [_objectCache removeObjectForKey:[object objectID]];
}

八、Core Data 的验证机制

8.1 属性验证

Core Data 提供了属性验证机制,确保数据的有效性:

// NSManagedObject 中属性验证的部分实现
@interface NSManagedObject ()

// 验证属性值
- (BOOL)_validateValue:(inout id *)ioValue forKey:(NSString *)key error:(NSError **)error;

// 子类可以重写的验证方法
- (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)key error:(NSError **)error;
- (BOOL)validateForInsert:(NSError **)error;
- (BOOL)validateForUpdate:(NSError **)error;
- (BOOL)validateForDelete:(NSError **)error;

@end

// 验证属性值的方法
- (BOOL)_validateValue:(inout id *)ioValue forKey:(NSString *)key error:(NSError **)error {
    // 获取属性描述
    NSAttributeDescription *attribute = [[self.entity attributesByName] objectForKey:key];
    
    if (!attribute) {
        // 如果不是属性,检查是否是关系
        NSRelationshipDescription *relationship = [[self.entity relationshipsByName] objectForKey:key];
        if (relationship) {
            // 验证关系
            return [self _validateRelationship:relationship value:ioValue error:error];
        }
        
        // 未知键
        if (error) {
            *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSUndefinedKeyError userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Object %@ has no attribute or relationship named %@", self, key]}];
        }
        return NO;
    }
    
    // 验证属性类型
    if (*ioValue != nil && ![self _isValidValue:*ioValue forAttribute:attribute]) {
        if (error) {
            *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSValidationTypeError userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Value %@ is not of the correct type for attribute %@", *ioValue, key]}];
        }
        return NO;
    }
    
    // 验证属性是否可为空
    if (*ioValue == nil && !attribute.allowsNull) {
        if (error) {
            *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSValidationMissingMandatoryPropertyError userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Attribute %@ cannot be nil", key]}];
        }
        return NO;
    }
    
    // 调用子类的验证方法
    return [self validateValue:ioValue forKey:key error:error];
}
8.2 关系验证

除了属性验证,Core Data 还支持关系验证:

// NSManagedObject 中关系验证的部分实现
- (BOOL)_validateRelationship:(NSRelationshipDescription *)relationship value:(inout id *)ioValue error:(NSError **)error {
    // 验证关系类型
    if (*ioValue != nil) {
        if (relationship.toMany) {
            // 多对多或一对多关系,值必须是集合
            if (![*ioValue isKindOfClass:[NSSet class]] && ![*ioValue isKindOfClass:[NSOrderedSet class]]) {
                if (error) {
                    *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSValidationTypeError userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Value %@ is not a valid collection type for to-many relationship %@", *ioValue, relationship.name]}];
                }
                return NO;
            }
            
            // 验证集合中的每个对象
            for (id object in (NSFastEnumeration *)*ioValue) {
                if (![object isKindOfClass:[NSManagedObject class]] || 
                    ![object.entity isSubentityOfEntity:relationship.destinationEntity]) {
                    if (error) {
                        *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSValidationTypeError userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Object %@ is not of the correct type for relationship %@", object, relationship.name]}];
                    }
                    return NO;
                }
            }
        } else {
            // 一对一关系,值必须是单个对象
            if (![*ioValue isKindOfClass:[NSManagedObject class]] || 
                ![(*ioValue).entity isSubentityOfEntity:relationship.destinationEntity]) {
                if (error) {
                    *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSValidationTypeError userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Object %@ is not of the correct type for relationship %@", *ioValue, relationship.name]}];
                }
                return NO;
            }
        }
    }
    
    // 验证反向关系的一致性
    if (relationship.inverseRelationship) {
        return [self _validateInverseRelationship:relationship value:ioValue error:error];
    }
    
    return YES;
}
8.3 验证流程

Core Data 的验证流程涉及以下关键步骤:

// NSManagedObjectContext 中验证的部分实现
- (BOOL)_validateChangesForSave:(NSError **)error {
    // 验证插入的对象
    for (NSManagedObject *object in [self insertedObjects]) {
        if (![object validateForInsert:error]) {
            return NO;
        }
    }
    
    // 验证更新的对象
    for (NSManagedObject *object in [self updatedObjects]) {
        if (![object validateForUpdate:error]) {
            return NO;
        }
    }
    
    // 验证删除的对象
    for (NSManagedObject *object in [self deletedObjects]) {
        if (![object validateForDelete:error]) {
            return NO;
        }
    }
    
    return YES;
}

// NSManagedObject 中验证对象插入的方法
- (BOOL)validateForInsert:(NSError **)error {
    // 验证所有属性
    for (NSAttributeDescription *attribute in [self.entity attributes]) {
        id value = [self valueForKey:attribute.name];
        if (![self _validateValue:&value forKey:attribute.name error:error]) {
            return NO;
        }
    }
    
    // 验证所有关系
    for (NSRelationshipDescription *relationship in [self.entity relationships]) {
        id value = [self valueForKey:relationship.name];
        if (![self _validateValue:&value forKey:relationship.name error:error]) {
            return NO;
        }
    }
    
    // 调用子类的验证方法
    if ([self respondsToSelector:@selector(validateForInsert:)]) {
        return [self performSelector:@selector(validateForInsert:) withObject:error];
    }
    
    return YES;
}

九、Core Data 的高级特性实现

9.1 Undo/Redo 机制

Core Data 支持强大的 Undo/Redo 功能,其实现涉及与 NSUndoManager 的集成:

// NSManagedObjectContext 中 Undo/Redo 的部分实现
@interface NSManagedObjectContext () {
    // 撤销管理器
    NSUndoManager *_undoManager;
    
    // 其他成员变量...
}

// 设置撤销管理器
@property (nullable, strong) NSUndoManager *undoManager;

// 注册撤销操作
- (void)_registerUndoWithTarget:(id)target selector:(SEL)selector object:(id)object;
- (void)_registerUndoForInsertedObject:(NSManagedObject *)object;
- (void)_registerUndoForDeletedObject:(NSManagedObject *)object;
- (void)_registerUndoForUpdatedObject:(NSManagedObject *)object;

@end

// 设置撤销管理器的方法
- (void)setUndoManager:(NSUndoManager *)undoManager {
    if (_undoManager != undoManager) {
        // 如果之前有撤销管理器,移除所有操作
        if (_undoManager) {
            [_undoManager removeAllActions];
        }
        
        _undoManager = undoManager;
        
        // 如果设置了新的撤销管理器,注册初始状态
        if (_undoManager) {
            [self _registerInitialStateWithUndoManager:_undoManager];
        }
    }
}

// 注册对象插入的撤销操作
- (void)_registerUndoForInsertedObject:(NSManagedObject *)object {
    if (!self.undoManager) return;
    
    [self.undoManager registerUndoWithTarget:self selector:@selector(_undoInsertObject:) object:object];
    [self.undoManager setActionName:[NSString stringWithFormat:@"Insert %@", [object.entity name]]];
}

// 撤销插入操作的方法
- (void)_undoInsertObject:(NSManagedObject *)object {
    [self deleteObject:object];
    [self.undoManager registerUndoWithTarget:self selector:@selector(_redoInsertObject:) object:object];
}

// 重做插入操作的方法
- (void)_redoInsertObject:(NSManagedObject *)object {
    [self insertObject:object];
    [self.undoManager registerUndoWithTarget:self selector:@selector(_undoInsertObject:) object:object];
}
9.2 惰性加载与预取

Core Data 实现了惰性加载和预取机制,提高数据访问效率:

// NSManagedObject 中惰性加载的部分实现
@interface NSManagedObject () {
    // 对象是否为故障状态
    BOOL _isFault;
    
    // 故障恢复信息
    NSDictionary *_faultContext;
    
    // 其他成员变量...
}

// 检查对象是否为故障状态
@property (readonly, getter=isFault) BOOL fault;

// 触发故障恢复
- (void)_awakeFromFetchWithRequest:(NSFetchRequest *)request context:(NSManagedObjectContext *)context;
- (void)_awakeFromInsert;
- (void)_turnIntoFault;

@end

// 检查对象是否为故障状态
- (BOOL)isFault {
    return _isFault;
}

// 访问属性时触发故障恢复
- (id)valueForKey:(NSString *)key {
    // 如果对象是故障状态,先触发恢复
    if (self.isFault) {
        [self _willAccessValueForKey:key];
    }
    
    // 调用父类实现
    return [super valueForKey:key];
}

// 触发故障恢复的方法
- (void)_willAccessValueForKey:(NSString *)key {
    if (self.isFault) {
        // 恢复对象
        [self _awakeFromFault];
    }
}

// NSFetchRequest 中预取的部分实现
@interface NSFetchRequest () {
    // 预取规则
    NSMutableDictionary *_relationshipKeyPathsForPrefetching;
    
    // 其他成员变量...
}

// 设置预取规则
- (void)setRelationshipKeyPathsForPrefetching:(nullable NSArray *)relationshipKeyPaths;
- (nullable NSArray *)relationshipKeyPathsForPrefetching;

@end

// 设置预取规则的方法
- (void)setRelationshipKeyPathsForPrefetching:(NSArray *)relationshipKeyPaths {
    if (!relationshipKeyPaths) {
        _relationshipKeyPathsForPrefetching = nil;
        return;
    }
    
    _relationshipKeyPathsForPrefetching = [NSMutableDictionary dictionary];
    for (NSString *keyPath in relationshipKeyPaths) {
        [_relationshipKeyPathsForPrefetching setObject:@YES forKey:keyPath];
    }
}
9.3 轻量级迁移实现

Core Data 的轻量级迁移机制允许在模型发生简单变化时自动迁移数据:

// NSPersistentStoreCoordinator 中轻量级迁移的部分实现
- (BOOL)_attemptLightweightMigrationToManagedObjectModel:(NSManagedObjectModel *)model forStoreAtURL:(NSURL *)storeURL error:(NSError **)error {
    // 检查源模型和目标模型是否兼容轻量级迁移
    NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeURL error:error];
    
    if (!sourceMetadata) {
        return NO;
    }
    
    NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:sourceMetadata];
    
    if (![model isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata]) {
        if (error) {
            *error = [NSError errorWithDomain:NSPersistentStoreCoordinatorErrorDomain code:NSPersistentStoreIncompatibleVersionHashError userInfo:@{NSLocalizedDescriptionKey: @"Model and store are incompatible"}];
        }
        return NO;
    }
    
    // 创建映射模型
    NSMappingModel *mappingModel = [NSMappingModel inferredMappingModelForSourceModel:sourceModel destinationModel:model error:error];
    
    if (!mappingModel) {
        return NO;
    }
    
    // 执行迁移
    return [mappingModel migrateStoreFromURL:storeURL
                                        type:NSSQLiteStoreType
                                     options:nil
                            withMappingModel:mappingModel
                            toDestinationURL:storeURL
                             destinationType:NSSQLiteStoreType
                          destinationOptions:nil
                                        error:error];
}

// 添加持久化存储时尝试轻量级迁移
- (NSPersistentStore *)addPersistentStoreWithType:(NSString *)storeType configuration:(NSString *)configuration URL:(NSURL *)storeURL options:(NSDictionary *)options error:(NSError **)error {
    // 检查是否启用了自动迁移
    BOOL shouldMigrateAutomatically = NO;
    BOOL shouldInferMappingModelAutomatically = NO;
    
    if (options) {
        shouldMigrateAutomatically = [options[NSPersistentStoreMigrateAutomaticallyOption] boolValue];
        shouldInferMappingModelAutomatically = [options[NSInferMappingModelAutomaticallyOption] boolValue];
    }
    
    // 如果启用了自动迁移,尝试轻量级迁移

九、Core Data 的高级特性实现(续)

9.3 轻量级迁移实现(续)
    // 如果启用了自动迁移,尝试轻量级迁移
    if (shouldMigrateAutomatically && shouldInferMappingModelAutomatically) {
        // 获取当前模型
        NSManagedObjectModel *currentModel = self.managedObjectModel;
        
        // 检查存储的元数据
        NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:storeType URL:storeURL error:error];
        
        if (storeMetadata) {
            // 检查存储的模型版本是否与当前模型兼容
            if (![currentModel isConfiguration:nil compatibleWithStoreMetadata:storeMetadata]) {
                // 尝试轻量级迁移
                if ([self _attemptLightweightMigrationToManagedObjectModel:currentModel forStoreAtURL:storeURL error:error]) {
                    // 迁移成功,继续添加存储
                } else {
                    // 轻量级迁移失败
                    if (error) {
                        *error = [NSError errorWithDomain:NSPersistentStoreCoordinatorErrorDomain code:NSPersistentStoreIncompatibleVersionHashError userInfo:@{NSLocalizedDescriptionKey: @"Lightweight migration failed"}];
                    }
                    return nil;
                }
            }
        }
    }
    
    // 继续常规的添加存储操作
    // ...
}

轻量级迁移支持以下类型的模型变化:

  1. 添加属性
  2. 删除属性
  3. 重命名属性(需要在模型中设置重命名映射)
  4. 更改属性的可选性
  5. 添加实体
  6. 删除实体(只要没有其他实体引用它)
9.4 批量操作

Core Data 支持批量操作,允许一次性处理大量数据:

// NSBatchUpdateRequest 类的部分实现
@interface NSBatchUpdateRequest : NSPersistentStoreRequest {
    // 更新的实体名称
    NSString *_entityName;
    
    // 更新的属性和值
    NSDictionary *_propertiesToUpdate;
    
    // 谓词条件
    NSPredicate *_predicate;
    
    // 返回类型
    NSBatchUpdateRequestResultType _resultType;
    
    // 其他成员变量...
}

// 初始化方法
- (instancetype)initWithEntityName:(NSString *)entityName;

// 设置更新的属性和值
@property (nonatomic, copy) NSDictionary *propertiesToUpdate;

// 设置谓词条件
@property (nonatomic, strong) NSPredicate *predicate;

// 设置返回类型
@property (nonatomic) NSBatchUpdateRequestResultType resultType;

@end

// NSBatchDeleteRequest 类的部分实现
@interface NSBatchDeleteRequest : NSPersistentStoreRequest {
    // 删除的实体名称
    NSString *_entityName;
    
    // 谓词条件
    NSPredicate *_predicate;
    
    // 是否合并更改
    BOOL _shouldMergeChanges;
    
    // 其他成员变量...
}

// 初始化方法
- (instancetype)initWithEntityName:(NSString *)entityName;

// 设置谓词条件
@property (nonatomic, strong) NSPredicate *predicate;

// 设置是否合并更改
@property (nonatomic) BOOL shouldMergeChangesIntoManagedObjectContexts;

@end

批量操作的执行流程:

// NSPersistentStoreCoordinator 中执行批量操作的方法
- (id)executeRequest:(NSPersistentStoreRequest *)request withContext:(NSManagedObjectContext *)context error:(NSError **)error {
    if ([request isKindOfClass:[NSBatchUpdateRequest class]]) {
        NSBatchUpdateRequest *updateRequest = (NSBatchUpdateRequest *)request;
        
        // 获取对应的存储
        NSPersistentStore *store = [self _storeForEntityName:updateRequest.entityName];
        
        if (!store) {
            if (error) *error = [NSError errorWithDomain:NSPersistentStoreCoordinatorErrorDomain code:NSPersistentStoreIncompatibleVersionHashError userInfo:nil];
            return nil;
        }
        
        // 在存储上执行批量更新
        return [store executeRequest:updateRequest withContext:context error:error];
    } else if ([request isKindOfClass:[NSBatchDeleteRequest class]]) {
        NSBatchDeleteRequest *deleteRequest = (NSBatchDeleteRequest *)request;
        
        // 获取对应的存储
        NSPersistentStore *store = [self _storeForEntityName:deleteRequest.entityName];
        
        if (!store) {
            if (error) *error = [NSError errorWithDomain:NSPersistentStoreCoordinatorErrorDomain code:NSPersistentStoreIncompatibleVersionHashError userInfo:nil];
            return nil;
        }
        
        // 在存储上执行批量删除
        return [store executeRequest:deleteRequest withContext:context error:error];
    }
    
    // 处理其他类型的请求...
    
    return nil;
}

十、Core Data 的性能优化

10.1 查询优化

Core Data 查询性能优化涉及以下关键技术:

  1. 索引使用
    • 为经常用于查询条件的属性添加索引,可以显著提高查询速度。
// 在数据模型中为属性添加索引
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];
NSAttributeDescription *attribute = [[entity attributesByName] objectForKey:@"lastName"];
attribute.indexed = YES;
  1. Fetch Limit 和 Offset
    • 使用 fetchLimitfetchOffset 实现分页查询,避免一次加载过多数据。
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
request.fetchLimit = 20;  // 每次只获取20条记录
request.fetchOffset = 40; // 从第41条记录开始获取
  1. Fetch Result Type
    • 根据需要选择合适的返回类型,避免不必要的数据加载。
// 只获取对象ID,而不是完整的对象
request.resultType = NSManagedObjectIDResultType;

// 只获取特定的属性值
request.propertiesToFetch = @[@"name", @"age"];
request.resultType = NSDictionaryResultType;
  1. 预取关系
    • 使用 relationshipKeyPathsForPrefetching 预取相关对象,减少后续查询。
request.relationshipKeyPathsForPrefetching = @[@"books"]; // 预取与Person关联的books
10.2 内存管理优化

Core Data 内存管理优化涉及以下关键技术:

  1. 对象缓存管理
    • 避免在内存中保留过多的托管对象,及时释放不再需要的对象。
// 将对象转换为故障状态,释放内存
[managedObjectContext refreshObject:object mergeChanges:NO];
  1. 分批处理大量数据
    • 对于大量数据,采用分批处理的方式,避免一次性加载所有数据。
NSInteger batchSize = 1000;
NSInteger offset = 0;

while (YES) {
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
    request.fetchLimit = batchSize;
    request.fetchOffset = offset;
    
    NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
    if (!results || results.count == 0) {
        break;
    }
    
    // 处理这批数据...
    
    offset += batchSize;
}
  1. 使用私有队列上下文
    • 在后台处理大量数据时,使用私有队列上下文,避免阻塞主线程。
NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
privateContext.parentContext = mainContext;

[privateContext performBlock:^{
    // 在后台处理大量数据
    // ...
    
    // 保存上下文
    NSError *error = nil;
    if ([privateContext save:&error]) {
        // 在主上下文中合并更改
        [mainContext performBlock:^{
            [mainContext save:nil];
        }];
    }
}];
10.3 存储优化

Core Data 存储优化涉及以下关键技术:

  1. 数据库配置
    • 合理配置 SQLite 数据库,如设置缓存大小、journal 模式等。
NSDictionary *options = @{
    NSSQLitePragmasOption: @{@"journal_mode": @"WAL"}, // 使用 WAL 模式提高写入性能
    NSSQLiteManualVacuumOption: @YES, // 允许手动执行 VACUUM 命令
};

NSPersistentStore *store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                          configuration:nil
                                                                    URL:storeURL
                                                                options:options
                                                                  error:&error];
  1. 批量操作
    • 使用批量操作减少事务开销,提高数据处理效率。
// 使用批量更新
NSBatchUpdateRequest *updateRequest = [[NSBatchUpdateRequest alloc] initWithEntityName:@"Person"];
updateRequest.propertiesToUpdate = @{@"age": @25};
updateRequest.predicate = [NSPredicate predicateWithFormat:@"age < 25"];

NSError *error = nil;
NSBatchUpdateResult *result = [managedObjectContext executeRequest:updateRequest error:&error];
  1. 数据库重构
    • 定期重构数据库,优化存储结构。
// 执行数据库 VACUUM 命令
NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: @YES};
NSError *error = nil;
BOOL success = [coordinator migratePersistentStore:store toURL:storeURL options:options withType:NSSQLiteStoreType error:&error];

十一、Core Data 与其他数据持久化方案的比较

11.1 与 Realm 的比较

Core Data 和 Realm 是 iOS 开发中常用的两种数据持久化方案,它们的比较如下:

  1. 性能

    • Realm 在写入性能上通常优于 Core Data,尤其是在大量数据写入时。
    • Core Data 在复杂查询和对象图管理方面表现更好。
  2. API 易用性

    • Realm 的 API 更加直观和易用,学习曲线较平缓。
    • Core Data 的 API 相对复杂,需要理解多个核心组件的交互。
  3. 跨平台支持

    • Realm 支持多平台(iOS、Android、React Native 等),而 Core Data 是 Apple 平台特有的。
  4. 社区与生态系统

    • Core Data 有更成熟的社区和生态系统,与其他 Apple 技术(如 NSFetchedResultsController)集成更好。
  5. 源码实现差异

    • Realm 是基于自己的数据库引擎实现的,而 Core Data 是基于 SQLite 等现有数据库技术。
11.2 与 SQLite 的比较

Core Data 与直接使用 SQLite 的比较如下:

  1. 抽象级别

    • Core Data 提供了更高的抽象级别,不需要直接编写 SQL 语句,开发效率更高。
    • 直接使用 SQLite 需要手动编写 SQL 语句,开发复杂度较高。
  2. 性能

    • 直接使用 SQLite 在某些特定场景下可能有更好的性能,因为可以精确控制 SQL 语句。
    • Core Data 在大多数情况下性能足够好,并且提供了自动优化(如查询缓存)。
  3. 功能丰富度

    • Core Data 提供了更多的高级功能,如对象图管理、变化跟踪、撤销/重做、轻量级迁移等。
    • 直接使用 SQLite 需要自己实现这些功能。
  4. 学习曲线

    • Core Data 的学习曲线较陡,需要理解多个核心组件和概念。
    • 直接使用 SQLite 相对简单,只需要了解 SQL 语法和 SQLite API。
11.3 与 UserDefaults 的比较

Core Data 与 UserDefaults 的比较如下:

  1. 数据类型支持

    • UserDefaults 只支持简单的数据类型(如 NSString、NSNumber、NSArray 等)。
    • Core Data 支持复杂的数据模型,包括实体、属性和关系。
  2. 数据量

    • UserDefaults 适用于少量数据的存储(通常用于应用设置)。
    • Core Data 适用于大量数据的存储和管理。
  3. 性能

    • UserDefaults 的读写性能较高,但不适用于复杂查询。
    • Core Data 在处理大量数据和复杂查询时性能更好。
  4. 使用场景

    • UserDefaults 主要用于存储应用的偏好设置。
    • Core Data 用于存储应用的核心数据,如联系人、笔记、相册等。

十二、Core Data 的最佳实践

12.1 模型设计最佳实践

Core Data 模型设计的最佳实践包括:

  1. 合理设计实体和关系

    • 根据业务需求合理设计实体和关系,避免过度设计。
    • 使用继承来组织相关实体,提高模型的可维护性。
  2. 使用轻量级迁移

    • 尽量使用轻量级迁移,减少迁移复杂度。
    • 在模型发生变化时,遵循轻量级迁移的规则,避免需要编写自定义迁移代码。
  3. 避免深嵌套关系

    • 深嵌套关系会增加查询和管理的复杂度。
    • 考虑使用扁平化的数据结构,或者通过中间实体来简化复杂关系。
  4. 为频繁查询的属性添加索引

    • 为经常用于查询条件的属性添加索引,提高查询性能。
12.2 代码实现最佳实践

Core Data 代码实现的最佳实践包括:

  1. 使用 NSFetchedResultsController

    • 对于 UITableView 和 UICollectionView 的数据源,优先使用 NSFetchedResultsController。
    • NSFetchedResultsController 提供了自动更新和动画支持,简化了数据展示和更新的代码。
  2. 合理使用多上下文架构

    • 根据应用需求合理使用多上下文架构,提高并发性能。
    • 主上下文用于 UI 相关操作,私有上下文用于后台处理。
  3. 避免阻塞主线程

    • 避免在主线程执行耗时的 Core Data 操作,如大量数据的导入或复杂查询。
    • 使用 performBlockperformBlockAndWait 在后台队列执行耗时操作。
  4. 正确处理错误

    • 在 Core Data 操作中始终检查错误,并进行适当的错误处理。
    • 对于可能失败的操作(如保存上下文),提供用户反馈。
12.3 测试与调试最佳实践

Core Data 测试与调试的最佳实践包括:

  1. 使用内存存储进行测试

    • 在单元测试和 UI 测试中使用内存存储(NSInMemoryStoreType),提高测试效率。
    • 内存存储不需要读写磁盘,测试速度更快。
  2. 启用 SQL 日志

    • 在调试时启用 SQL 日志,查看实际执行的 SQL 语句。
    • 通过设置环境变量 “com.apple.CoreData.SQLDebug” 为 1 来启用 SQL 日志。
  3. 编写单元测试

    • 编写单元测试验证 Core Data 代码的正确性。
    • 测试内容包括数据的增删改查、关系的维护、验证逻辑等。
  4. 使用 Instruments 进行性能分析

    • 使用 Instruments 分析 Core Data 应用的性能瓶颈。
    • 关注内存使用、SQL 查询性能等指标。

十三、Core Data 的未来发展趋势

13.1 与 SwiftUI 的集成

随着 SwiftUI 的普及,Core Data 与 SwiftUI 的集成将更加紧密:

  1. 直接绑定

    • 未来可能会提供更直接的数据绑定机制,使 Core Data 与 SwiftUI 的状态管理更加无缝。
  2. 声明式查询

    • 可能会引入声明式的查询 API,与 SwiftUI 的声明式编程风格一致。
  3. 简化数据展示

    • 提供更简单的方式在 SwiftUI 视图中展示 Core Data 数据,减少样板代码。
13.2 性能优化

未来 Core Data 可能会在性能方面进行更多优化:

  1. 更好的内存管理

    • 提供更精细的内存管理控制,减少内存占用。
    • 优化对象缓存机制,提高内存使用效率。
  2. 更快的查询执行

    • 优化查询执行引擎,提高复杂查询的性能。
    • 进一步优化与 SQLite 的交互,减少不必要的开销。
  3. 并行处理

    • 利用多核处理器进行并行数据处理,提高大数据集的处理速度。
13.3 跨平台支持

虽然 Core Data 目前是 Apple 平台特有的,但未来可能会有跨平台支持的发展:

  1. Swift 多平台支持

    • 随着 Swift 对多平台的支持不断增强,Core Data 可能会扩展到其他平台。
  2. 与其他数据库的集成

    • 支持与更多类型的数据库集成,如 MongoDB、Firebase 等。
    • 提供统一的 API 访问不同类型的数据库。
13.4 简化 API

未来 Core Data 可能会简化其 API,降低学习曲线:

  1. 更现代的 API

    • 提供更符合 Swift 语言特性的 API,如使用 Result 类型处理错误。
    • 减少对 Objective-C 风格 API 的依赖。
  2. 减少样板代码

    • 减少使用 Core Data 时需要编写的样板代码。
    • 提供更简单的初始化和配置方法。
  3. 自动代码生成

    • 增强 Xcode 的代码生成功能,自动生成更多的 Core Data 相关代码。
13.5 与云服务的集成

Core Data 可能会进一步加强与 Apple 云服务的集成:

  1. CloudKit 集成

    • 简化 Core Data 与 CloudKit 的同步,提供更无缝的云存储体验。
  2. 多设备同步

    • 提供更简单的方式实现 Core Data 数据在多个设备之间的同步。
  3. 后台同步

    • 优化后台同步机制,减少对用户设备性能的影响。

十四、Core Data 的常见陷阱与解决方案

14.1 线程安全问题

陷阱:在多个线程中共享同一个 NSManagedObjectContext 实例,导致数据不一致或崩溃。

解决方案

  • 为每个线程创建独立的 NSManagedObjectContext 实例。
  • 使用父子上下文架构,子上下文在后台线程处理数据,主上下文在主线程更新 UI。
  • 使用 performBlockperformBlockAndWait 方法确保所有操作在上下文的队列上执行。
14.2 内存泄漏问题

陷阱:长时间保留大量托管对象,导致内存占用过高。

解决方案

  • 及时释放不再需要的托管对象,将其转换为故障状态。
  • 使用 fetchLimitfetchOffset 实现分页查询,避免一次加载过多数据。
  • 在处理大量数据时,使用私有队列上下文并分批处理。
14.3 关系维护问题

陷阱:未能正确维护实体之间的关系,导致数据不一致。

解决方案

  • 在模型中正确定义反向关系,确保关系的一致性。
  • 在代码中同时更新双向关系,避免只更新一方。
  • 使用级联删除规则处理相关对象的删除。
14.4 迁移问题

陷阱:模型更新后未正确处理数据迁移,导致应用崩溃或数据丢失。

解决方案

  • 在开发过程中尽早规划数据模型,减少后期模型变更的可能性。
  • 使用轻量级迁移处理简单的模型变更。
  • 对于复杂的模型变更,编写自定义迁移代码。
  • 在应用更新时,提供适当的错误处理和用户反馈。
14.5 性能问题

陷阱:查询性能低下,影响应用响应速度。

解决方案

  • 为经常用于查询条件的属性添加索引。
  • 使用 relationshipKeyPathsForPrefetching 预取相关对象,减少后续查询。
  • 避免在循环中执行查询,尽量批量处理。
  • 使用 Instruments 分析性能瓶颈,针对性地进行优化。

十五、Core Data 实战案例分析

15.1 小型应用案例

假设我们正在开发一个简单的笔记应用,使用 Core Data 存储笔记数据。

  1. 数据模型设计

    • 设计两个实体:Note 和 Tag
    • Note 实体包含属性:title、content、date
    • Tag 实体包含属性:name
    • Note 和 Tag 之间是多对多关系
  2. Core Data 堆栈设置

    • 创建主上下文,与主线程关联
    • 设置轻量级迁移选项,以便未来模型更新
  3. 数据操作实现

    • 实现添加笔记、删除笔记、修改笔记的方法
    • 实现添加标签、删除标签的方法
    • 实现根据标签筛选笔记的查询方法
  4. 与 UI 集成

    • 使用 NSFetchedResultsController 显示笔记列表
    • 实现笔记详情视图,展示和编辑笔记内容
15.2 大型应用案例

假设我们正在开发一个社交网络应用,使用 Core Data 存储用户数据、好友关系、消息等。

  1. 数据模型设计

    • 设计多个实体:User、Friendship、Message、Post、Comment 等
    • 设计复杂的关系,如用户之间的多对多好友关系、用户与帖子的一对多关系等
  2. Core Data 堆栈设置

    • 采用多上下文架构,包括主上下文、私有上下文
    • 设置多个持久化存储,将不同类型的数据存储到不同的数据库文件中
  3. 性能优化

    • 为经常查询的属性添加索引
    • 使用批量操作处理大量数据
    • 实现分页查询,避免一次加载过多数据
  4. 并发处理

    • 使用后台线程处理耗时的数据导入和导出
    • 实现线程安全的数据访问机制
  5. 数据迁移策略

    • 设计合理的模型版本控制策略
    • 实现轻量级迁移和自定义迁移代码
15.3 与其他技术集成案例

假设我们正在开发一个混合应用,需要将 Core Data 与其他技术集成。

  1. 与 CloudKit 集成

    • 实现 Core Data 与 CloudKit 的数据同步
    • 处理云端和本地数据冲突
  2. 与 REST API 集成

    • 实现 Core Data 与服务器端 REST API 的数据同步
    • 设计本地缓存策略,确保离线使用
  3. 与 SwiftUI 集成

    • 使用 @FetchRequest 属性包装器获取 Core Data 数据
    • 实现数据变化时自动更新 SwiftUI 视图
  4. 与第三方库集成

    • 集成第三方库(如 RxSwift)处理 Core Data 数据
    • 使用 Reactive 编程模式简化数据处理流程

十六、Core Data 的高级技巧与黑科技

16.1 使用表达式和函数

Core Data 支持在查询中使用各种表达式和函数:

// 使用聚合函数
NSExpressionDescription *countExpressionDescription = [[NSExpressionDescription alloc] init];
[countExpressionDescription setName:@"count"];
[countExpressionDescription setExpression:[NSExpression expressionForFunction:@"count:" arguments:@[[NSExpression expressionForKeyPath:@"name"]]]];
[countExpressionDescription setExpressionResultType:NSInteger64AttributeType];

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
[request setPropertiesToFetch:@[countExpressionDescription]];
[request setResultType:NSDictionaryResultType];

// 使用自定义表达式
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SUBSTRING(name, 0, 1) == %@", @"A"];
[request setPredicate:predicate];
16.2 使用原始 SQL 查询

在某些特殊情况下,可以使用原始 SQL 查询:

// 执行原始 SQL 查询
NSString *sql = @"SELECT * FROM Person WHERE age > 18";
NSArray *results = [managedObjectContext executeFetchRequest:request withSQL:sql error:&error];

// 执行原始 SQL 插入/更新/删除
NSString *updateSQL = @"UPDATE Person SET age = age + 1 WHERE name LIKE 'A%'";
BOOL success = [managedObjectContext executeRequest:request withSQL:updateSQL error:&error];
16.3 自定义持久化存储

Core Data 允许创建自定义的持久化存储:

// 创建自定义持久化存储类
@interface MyCustomStore : NSPersistentStore
@end

@implementation MyCustomStore

// 实现必要的方法
- (BOOL)load:(NSError **)error {
    // 实现存储加载逻辑
    return YES;
}

- (id)executeRequest:(NSPersistentStoreRequest *)request withContext:(NSManagedObjectContext *)context error:(NSError **)error {
    // 实现请求执行逻辑
    return nil;
}

// 其他必要的方法...

@end

// 注册自定义存储类型
[NSClassFromString(@"NSPersistentStoreCoordinator") registerStoreClass:[MyCustomStore class] forStoreType:@"MyCustomStoreType"];
16.4 使用 Core Data 扩展

Core Data 提供了多种扩展点,可以自定义其行为:

// 自定义 NSManagedObject 子类
@interface Person : NSManagedObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSNumber *age;

// 自定义方法
- (void)incrementAge;

@end

@implementation Person

- (void)incrementAge {
    self.age = @([self.age integerValue] + 1);
}

// 验证方法
- (BOOL)validateName:(id *)ioValue error:(NSError **)outError {
    NSString *name = *ioValue;
    if (name.length == 0) {
        if (outError) {
            *outError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSValidationMissingMandatoryPropertyError userInfo:@{NSLocalizedDescriptionKey: @"Name cannot be empty"}];
        }
        return NO;
    }
    return YES;
}

@end

// 自定义 NSManagedObjectContext 子类
@interface MyManagedObjectContext : NSManagedObjectContext

// 自定义保存方法
- (BOOL)saveWithValidation:(NSError **)error;

@end

@implementation MyManagedObjectContext

- (BOOL)saveWithValidation:(NSError **)error {
    // 执行额外的验证
    if (![self _validateAllObjects:error]) {
        return NO;
    }
    
    // 调用父类方法
    return [super save:error];
}

@end
16.5 使用 Core Data 与后台任务

在后台任务中使用 Core Data 需要特别注意:

// 在后台任务中使用 Core Data
__block UIBackgroundTaskIdentifier backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
    // 任务超时处理
    [application endBackgroundTask:backgroundTask];
    backgroundTask = UIBackgroundTaskInvalid;
}];

// 创建私有队列上下文
NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
privateContext.parentContext = mainContext;

[privateContext performBlock:^{
    // 在后台执行数据操作
    // ...
    
    // 保存上下文
    NSError *error = nil;
    if ([privateContext save:&error]) {
        // 在主上下文中合并更改
        [mainContext performBlock:^{
            [mainContext save:nil];
            
            // 结束后台任务
            [application endBackgroundTask:backgroundTask];
            backgroundTask = UIBackgroundTaskInvalid;
        }];
    } else {
        // 处理错误
        [application endBackgroundTask:backgroundTask];
        backgroundTask = UIBackgroundTaskInvalid;
    }
}];

十七、Core Data 的常见错误处理

17.1 数据库锁错误

错误描述:数据库被锁定,无法执行操作。

可能原因

  • 多个上下文同时尝试写入同一数据库。
  • 长时间持有事务不提交。

解决方案

  • 确保在多线程环境中正确使用上下文。
  • 尽量缩短事务的持续时间。
  • 实现适当的重试机制。
17.2 模型版本不匹配错误

错误描述:持久化存储的模型版本与当前应用的模型不匹配。

可能原因

  • 应用更新后,数据模型发生变化,但未正确处理迁移。
  • 手动修改了数据库文件。

解决方案

  • 实现数据迁移机制,包括轻量级迁移和自定义迁移。
  • 在应用启动时检查模型版本,必要时执行迁移。
  • 提供数据恢复选项,在迁移失败时保护用户数据。
17.3 验证错误

错误描述:对象验证失败,无法保存。

可能原因

  • 属性值不符合模型定义的约束条件。
  • 关系未正确维护。

解决方案

  • 在保存前手动验证对象。
  • 实现自定义验证逻辑,确保数据的有效性。
  • 提供用户友好的错误提示,帮助用户修正数据。
17.4 内存不足错误

错误描述:应用因内存不足被系统终止。

可能原因

  • 缓存了过多的托管对象。
  • 处理大量数据时未进行适当的内存管理。

解决方案

  • 及时释放不再需要的托管对象。
  • 使用 refreshObject:mergeChanges: 将对象转换为故障状态。
  • 分批处理大量数据,避免一次性加载过多。
17.5 线程安全错误

错误描述:在错误的线程上访问上下文或对象。

可能原因

  • 在创建上下文的线程之外的线程访问上下文。
  • 在不同线程之间共享托管对象,而未使用对象 ID。

解决方案

  • 始终在上下文的队列上执行操作,使用 performBlockperformBlockAndWait
  • 在不同线程之间传递对象 ID,而不是直接传递对象。
  • 为每个线程创建独立的上下文。

十八、Core Data 与其他 Apple 技术的集成

18.1 与 NSFetchedResultsController 的集成

NSFetchedResultsController 是一个专门为 UITableView 和 UICollectionView 设计的控制器,它可以自动跟踪 Core Data 数据的变化并更新视图:

// 设置 NSFetchedResultsController
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
fetchRequest.sortDescriptors = @[sortDescriptor];

NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                                        managedObjectContext:self.managedObjectContext
                                                                                          sectionNameKeyPath:nil
                                                                                                   cacheName:nil];
controller.delegate = self;

// 实现 NSFetchedResultsControllerDelegate 方法
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeUpdate:
            [self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
            
        case NSFetchedResultsChangeMove:
            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}
18.2 与 CloudKit 的集成

Core Data 可以与 CloudKit 集成,实现数据的云端同步:

// 设置 CloudKit 容器
CKContainer *container = [CKContainer defaultContainer];
CKDatabase *database = [container privateCloudDatabase];

// 创建导出操作
NSBatchExportRequest *exportRequest = [[NSBatchExportRequest alloc] initWithEntityName:@"Person"];
exportRequest.predicate = [NSPredicate predicateWithFormat:@"needsSync == YES"];

// 执行导出操作
[managedObjectContext executeRequest:exportRequest completionHandler:^(NSBatchExportResult * _Nullable result, NSError * _Nullable error) {
    if (error) {
        // 处理错误
        return;
    }
    
    // 获取导出的数据
    NSArray *metadataObjects = result.metadataObjects;
    
    // 上传到 CloudKit
    for (NSCKExportMetadata *metadata in metadataObjects) {
        CKRecord *record = [self recordFromMetadata:metadata];
        [database saveRecord:record completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {
            if (!error) {
                // 更新本地对象的同步状态
                [self markObjectAsSynced:metadata.objectID];
            }
        }];
    }
}];

// 创建导入操作
NSBatchImportRequest *importRequest = [[NSBatchImportRequest alloc] initWithEntityName:@"Person"];
importRequest.predicate = [NSPredicate predicateWithFormat:@"modified > %@", lastSyncDate];

// 执行导入操作
[managedObjectContext executeRequest:importRequest completionHandler:^(NSBatchImportResult * _Nullable result, NSError * _Nullable error) {
    if (error) {
        // 处理错误
        return;
    }
    
    // 合并导入的数据
    [self mergeImportedData:result.importedObjects];
}];

你可能感兴趣的:(Swift语言进阶,swift,jvm,开发语言)