【问题标题】:Altering ManagedObjects In NSArray更改 NSArray 中的 ManagedObjects
【发布时间】:2010-04-20 08:50:40
【问题描述】:

我有一个名为“Job”的实体,它有两个布尔属性,名为“completed”和“logged”。 我正在尝试检索在应用程序启动时尚未记录的所有已完成作业并将它们更改为已记录。我可以通过这个 fetchRequest 获得所有已完成但未记录的作业:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(completed == %@ && logged == %@)", [NSNumber numberWithBool:YES], [NSNumber numberWithBool:NO]];

然后我将此谓词分配给 fetchRequest 并调用 [managedObjectContext executeFetchRequest:fetchRequest] 方法来获取满足此条件的所有 Job 实体的数组。这似乎工作正常,并且返回了正确数量的工作。

我一直在尝试做的是遍历返回的 NSArray,将日志属性设置为 YES,然后保存。这似乎已完成并且不会返回任何错误,但是当应用程序退出时更改不会保留。我哪里错了?

[fetchRequest setPredicate:predicate];
NSError error;
NSArray jobsToLog = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if ([jobsToLog count] > 0) {
   for (int i = 0; i < [jobsToLog count] - 1; i++) {
      [[jobsToLog objectAtIndex:i] setLogged:[NSNumber numberWithBool:YES]];
      // Commit the changes made to disk
      error = nil;
      if (![managedObjectContext save:&error]) {
         // An error occurred
      }
   }
}

感谢期待,

【问题讨论】:

    标签: iphone objective-c core-data nsarray


    【解决方案1】:

    首先,您可以通过以下方式清理一下:

    [fetchRequest setPredicate:predicate];
    NSError *error = nil;
    NSArray jobsToLog = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
    NSAssert1(error == nil, @"Error retrieving jobs: %@", [error userInfo]);
    for (id job in jobsToLog) {
      [job setValue:[NSNumber numberWithBool:YES] forKey:@"logged"];
    }
    if (![managedObjectContext save:&error]) {
      NSAssert1(NO, @"Failed to save %@", [error userInfo]);
    }
    
    • 请注意,我以 error 为 nil 并作为指针开始(您的声明不是)。如果你不这样做,那么该指针的初始状态是未定义的,绝对不是 nil。
    • 检查以确保提取中没有错误。
    • 不需要对计数进行检查,因为快速枚举器会为您处理。
    • 在每个对象之后保存是浪费,除非您有数千个对象,否则在最后保存。
    • 在调试器中遍历您的代码,并确保您正在获取对象并在它们上循环。

    【讨论】:

    • 非常感谢!比我编写的代码更简洁:)
    【解决方案2】:

    一些可能有帮助的注释:

    for 循环从 0 循环到小于计数的 1。这将跳过最后一个作业。如果只有一份工作,什么都不会发生。将循环更改为:

    for (int i = 0; i < [jobsToLog count]; i++)
    

    或

    for (int i = 0; i <= [jobsToLog count] - 1; i++)
    

    当从 NSArray 中提取对象时,编译器将不知道它的类型。您应该明确地转换对象:

      [(Job *)[jobsToLog objectAtIndex:i] setLogged:[NSNumber numberWithBool:YES]];
    

    您可以使用快速枚举完成上述两项工作:

    for(Job *thisJob in jobsToLog) {
      [thisJob setLogged:[NSNumber numberWithBool:YES];
    }
    

    【讨论】:

    • 强制转换是完全没有必要的,因为你得到了一个 id,只要让类知道该方法通过导入存在,它就会接受任何方法调用。 99.9% 的时间,在 Objective-C 中的转换都是错误的。
    • @Marcus S. Zarra:你能为我解释一下你的评论吗?我一直在思考它,并没有完全理解为什么使用 id 比在数组中显式转换你所期望的更好。
    【解决方案3】:

    如果使用KVC(Key Value Coding)方法会怎样:

    [[jobsToLog objectAtIndex:i] setValue:[NSNumber numberWithBool:YES] forKey:@"logged"];
    

    您的自定义 NSManagedObject 类中有 setLogged 方法吗?

    【讨论】:

      【解决方案4】:

      我不是这里的专家,但我认为您需要通过使用 setPrimitiveValue: 来告知托管对象上下文来进行更改。所以试试这个。

      [self willChangeValueForKey:@"logged"];
      [self setPrimitiveValue:[NSNumber numberWithBool:YES] forKey:@"logged"];
      [self didChangeValueForKey:@"logged"];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-31
        • 1970-01-01
        • 2012-01-12
        • 1970-01-01
        • 2010-12-19
        相关资源
        最近更新 更多