gpt4 book ai didi

objective-c - NSFetchedResultsController 更新和一对一关系的问题

转载 作者:搜寻专家 更新时间:2023-10-30 19:46:50 25 4
gpt4 key购买 nike

我在使用具有简单一对一关系的 NSFetchedResultsController 进行插入时遇到了一些问题。当我创建一个与 Target 对象具有一对一关系的新 Source 对象时,它似乎调用 - [(void)controller:(NSFetchedResultsController *)controller didChangeObject ... ] 两次,同时使用 NSFetchedResultsChangeInsert 和 NSFetchedResultsChangeUpdate 类型,这会导致 tableview 在更新后立即显示不准确的数据。

我可以使用基于 XCode 在基于导航的 CoreData 应用程序中生成的标准模板项目的简单示例来重新创建它。该模板创建一个具有 timeStamp 属性的 Event 实体。我想向此事件添加一个新实体“标签”,它与实体只是一对一的关系,其想法是每个事件都有来自某个标签列表的特定标签。我在核心数据编辑器中创建了从事件到标签的关系,以及从标签到事件的反向关系。然后我为 Event 和 Tag 生成 NSManagedObject 子类,这是非常标准的:

@interface Event : NSManagedObject {
@private
}
@property (nonatomic, retain) NSDate * timeStamp;
@property (nonatomic, retain) Tag * tag;

and
@interface Tag : NSManagedObject {
@private
}
@property (nonatomic, retain) NSString * tagName;
@property (nonatomic, retain) NSManagedObject * event;

然后我在启动时用一些数据预先填充了 Tags 实体,这样我们就可以在插入新事件时从 Tag 中进行选择。在 AppDelegate 中,在返回 persistentStoreCoordinator 之前调用它:

NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Tag" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
//check if Tags haven't already been created. If not, then create them
if (fetchedObjects.count == 0) {
NSLog(@"create new objects for Tag");

Tag *newManagedObject1 = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:context];
newManagedObject1.tagName = @"Home";

Tag *newManagedObject2 = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:context];
newManagedObject2.tagName = @"Office";

Tag *newManagedObject3 = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:context];
newManagedObject3.tagName = @"Shop";
}

[fetchRequest release];

if (![context save:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}

现在,我更改了 insertNewObject 代码以将标签添加到我们要插入的事件属性中。对于这个例子,我只是从 fetchedObjects 列表中选择第一个:

- (void)insertNewObject
{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
Event *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
// If appropriate, configure the new managed object.
// Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
[newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityTag = [NSEntityDescription entityForName:@"Tag" inManagedObjectContext:context];
[fetchRequest setEntity:entityTag];
NSError *errorTag = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&errorTag];
if (fetchedObjects.count > 0) {
Tag *newtag = [fetchedObjects objectAtIndex:0];
newManagedObject.tag = newtag;
}

// Save the context.
NSError *error = nil;
if (![context save:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}

我现在想看到反射(reflect)这些变化的 TableView ,所以我让 UITableViewCell 键入 UITableViewCellStyleSubtitle 并更改 configureCell 以在详细信息文本标签中显示 tagName:

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
Event *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[managedObject valueForKey:@"timeStamp"] description];
cell.detailTextLabel.text = managedObject.tag.tagName;
}

现在一切就绪。当我调用 insertNewObject 时,它似乎可以很好地创建第一行,但第二行是第一行的副本,即使时间戳应该相隔几秒钟: enter image description here

当我上下滚动屏幕时,它会刷新行,然后在正确的时间显示正确的结果。当我单步执行代码时,出现了核心问题:插入新行似乎调用了 [(NSFetchedResultsController *)controller didChangeObject ...] 两次,一次用于插入,一次用于更新。我不确定为什么调用更新。关键是:如果我移除 Event 和 Tag 之间的反向关系,插入将开始正常工作!只有插入被调用,该行没有被复制,并且一切正常。

那么导致 NSFetchedResultsController 委托(delegate)方法被调用两次的反向关系是什么?在这种情况下我应该没有他们生活吗?我知道如果未指定逆函数,XCode 会发出警告,这似乎是个坏主意。我在这里做错了什么吗?这是已知解决方法的已知问题吗?

谢谢。

最佳答案

关于 didChangeObject 被多次调用的问题,我找到了发生这种情况的原因之一。如果您的 Controller 中有多个共享 NSManagedObjectContextNSFetchedResultsController,当数据发生变化时,didChangeObject 将被多次调用。我偶然发现了同样的问题,经过一系列测试后,我注意到了这种行为。我还没有测试如果 NSFetchedResultsControllers 不共享 NSManagedObjectContext 是否会发生此行为。不幸的是,didChangeObject 没有告诉哪个 NSFetchedResultsController 触发了更新。为了实现我的目标,我最终在我的代码中使用了一个标志。

希望这对您有所帮助!

关于objective-c - NSFetchedResultsController 更新和一对一关系的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6658914/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com