首页 > 解决方案 > 保持内存中的核心数据对象不被不相关的代码删除?

问题描述

我正在开发一个写得非常糟糕的旧 Objective-C 应用程序。我正在研究的功能涉及从核心数据中获取不同的记录类型并将它们发送到服务器。并且必须先发送一种记录类型 (A),然后才能发送另一种记录类型 (B)。

编辑:AActivitySession对象和BActivityRun对象。

这就是问题所在:在应用程序的某个地方,有某种监听器在发送 A 记录后删除了所有 B 记录。我花了一段时间试图弄清楚这发生在哪里,但我没有运气。我的解决方案是在发送 A 记录之前将所有 B 记录加载到内存中(认为即使 B 记录从核心数据中删除,它们仍将存在于内存中)。但是我发现在从核心数据中删除 B 记录后,我的记录数组也被清除了。

这是我正在谈论的逻辑的核心:

__block NSArray* activityRuns = [coreData fetchByEntitiyName:@"ActivityRun"];

NSLog(@"---> Sending %@ students", @([students count]));
return [self sendStudents:students withApiKey:apiKey]
.then(^{
  // This must happen before sending anything with activity references
  NSLog(@"---> Fetching activities");
  return [self fetchActivitiesWithApiKey:apiKey];
})
.then(^{
  NSArray* data = [coreData fetchByEntitiyName:@"ActivitySession"];
  NSLog(@"---> Sending %@ activity sessions", @([data count]));
  return [self sendActivitySessions:data withApiKey:apiKey].catch(failLogger(@"Failed to upload activity sessions", nil));
})
.then(^{
  NSLog(@"---> Sending %@ activity runs", @([activityRuns count]));
  return [self sendActivityRuns:activityRuns withApiKey:apiKey].catch(failLogger(@"Failed to upload activity runs", nil));
})

activityRuns是我要发送的内存数据(使用[self sendActivityRuns:activityRuns withApiKey:apiKey])。这是如何fetchByEntitiyName定义的:

- (NSArray*) fetchByEntitiyName:(NSString*) entityName {
    NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName];
    NSError* error = nil;
    NSArray* results = [_mainQueueContext executeFetchRequest:fetchRequest error:&error];
    if (results == nil) {
            ELog(@"--- Failed to fetch %@: %@", entityName, error);
            return @[];
    }
    return results;
}

activityRuns除了在上面的代码片段中,每个活动运行都是使用 HTTP 请求发送的,其他任何地方都没有使用/传递。我尝试在创建数组之后(对象有效并包含数据)和发送之前(它们都是nil)添加断点。

当某些东西删除记录时,如何防止核心数据在我的内存对象上出现问题?

标签: iosobjective-ccore-data

解决方案


有几种方法可以做到这一点:

  • 最明显的是调用 NSManagedObjectContext.deleteObject,只需在其中查找deleteObject并放置断点即可。
  • 另一种是如果 A 和 B 有级联删除的关系,并且您删除了父级,则 B 被删除。例如,如果学生在以下属性中有一个 ActivityRun-s 列表:student.activityRuns(子对象数组)或反向属性 - activityRun.student(单个父对象),并且在您的 CoreData 模型中设置了此属性作为级联删除,如果你删除一个学生,所有的 activityRuns 都将消失。如果您使用“on delete set null”而不是“on delete cascade”,则不会自动删除子级,但您必须在需要时手动删除它们。另一种方法是通过设置将孩子与父母“分离” activityRun.student = nil;,它应该具有相同的效果(再次必须在需要时手动删除)。
  • 另一种选择是,如果您对此数据库执行原始 SQL DELETE 查询

有一种方法可以查看后台发生的所有 CoreData SQL 命令 -请参见此处


推荐阅读