我有一个NSFetchedResultsController
从CoreData商店获取数据。当初始化frc时,我调用performFetch
并检查frc.fetchedObjects
中获取的对象的数量,结果为0,应该是。
在代码的另一个地方我打电话:
[obj.managedObjectContext refreshObject:obj mergeChanges:NO]
虽然我甚至不确定它是否需要它的副作用是导致frc获取一些最初未获取的对象,并且考虑到所使用的查询,不应该取出。这些对象与refreshObject:mergeChanges:
调用的对象完全相同。
为什么会这样?
编辑:
此查询不会发生:
query.predicate = [NSPredicate predicateWithFormat:@"(cartEntry != NULL) AND (urlWeb = NULL)", version, dateUrlExpire];
frc = [[NSFetchedResultsController alloc] initWithFetchRequest:query managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
frc.delegate = self;
[frc performFetch:&error];
但是当我将查询更改为此版本时,所有记录都会发生(urlWebVersion
和urlWebDate
为NULL
):
query.predicate = [NSPredicate predicateWithFormat:@"(cartEntry != NULL) AND ((urlWeb = NULL) OR (urlWebVersion != %@) OR (urlWebDate > %@))", version, dateUrlExpire];
*编辑#2 *
这是一个显示奇怪行为的最小代码示例(执行期间没有错误):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSError *error;
// Create an empty entity with the optional fields attr1 (string) and attr2 (date)
Entity *e = [NSEntityDescription insertNewObjectForEntityForName:@"Entity" inManagedObjectContext:[self managedObjectContext]];
// Save entity
[_managedObjectContext save:&error];
// Setup fetched results controller
NSPredicate *pred = [NSPredicate predicateWithFormat:@"(attr1 != %@) AND (attr2 != %@)", @"", [NSDate new], nil];
NSFetchRequest *query = [[NSFetchRequest alloc] initWithEntityName:@"Entity"];
query.predicate = pred;
query.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"attr1" ascending:NO]];
frc = [[NSFetchedResultsController alloc] initWithFetchRequest:query managedObjectContext:_managedObjectContext sectionNameKeyPath:nil cacheName:nil];
frc.delegate = self;
// Load data
[frc performFetch:&error];
// Output #1
NSLog(@"%ld", frc.fetchedObjects.count);
[_managedObjectContext refreshObject:e mergeChanges:NO];
return YES;
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
NSLog(@"%ld", controller.fetchedObjects.count);
}
输出:
2015-01-22 22:53:44.293 CoreDataBug[10740:1445186] 0
2015-01-22 22:53:44.317 CoreDataBug[10740:1445186] 1
答案 0 :(得分:2)
您的问题是NSPredicate难以将!=
与零值匹配。例如,在你的编辑2中:
[NSPredicate predicateWithFormat:@"(attr1 != %@) AND (attr2 != %@)",
@"", [NSDate new], nil];
如您所知,在获取请求后返回零。 (那里有一个额外的零,但它不会影响任何东西)。但改为:
NSPredicate *pred = [NSPredicate predicateWithFormat:
@"((attr1 != %@) || (attr1 == nil)) AND ((attr2 != %@) || (attr2 == nil))",
@"", [NSDate new]];
确实返回实体,即使逻辑上它们是相同的。
这是记录在案的行为,虽然很难遵循这样的反直觉,但请参阅Predicate Programming Guide中的“使用空值”小节。
目前还不清楚为什么刷新对象会导致谓词突然匹配;这可能是一个错误。但是,鉴于上述文档,!=
不应用于可能为零的值(除非在没有配对!= nil
的情况下检查|| (x = nil)
)。不止一点烦人和反直觉。