保持内存中的核心数据对象不被不相关的代码删除?

时间:2018-05-11 21:47:58

标签: ios objective-c core-data

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

编辑:A引用ActivitySession个对象,B引用ActivityRun个对象。

问题在于:在应用程序的某个地方,某些侦听器会在发送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)。

当某些内容删除记录时,如何防止核心数据与我的内存中对象发生冲突?

1 个答案:

答案 0 :(得分:1)

有几种方法可以实现:

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

有一种方法可以看到发生在幕后的所有CoreData SQL命令 - see here