更正Core Data应用程序中的NSTableView的正确方法 [英] Correct way of updating an NSTableView in a Core Data app

查看:139
本文介绍了更正Core Data应用程序中的NSTableView的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个核心数据项目与NSTableView其中的列绑定到一个NSArrayController。反过来,控制器的内容绑定到AppDelegate的主要管理对象上下文。

I have a Core Data project with an NSTableView where the columns are bound to an NSArrayController. In turn, the controller's content is bound to the main managed object context of the AppDelegate.

我已经对NSTextFieldCell进行了子类化,以提供一种更加定制的方式显示数据。一切似乎工作良好,但是当我枚举通过上下文中的对象和更改一个属性,NSArrayController似乎没有传递新的值通过到表。我知道他们正在改变为sortDescriptors工作,表组织本身根据新的数据,但仍显示旧的值。我猜这是回收的NSCell的显示数据:虽然底层的价值观在Core Data DB中改变了,他们没有重新绘制。

I've sub-classed NSTextFieldCell's to provide a more customised way of displaying the data. Everything seems to work well but when I enumerate through the objects in the context and change an attribute, the NSArrayController doesn't seem to pass the new values through to the table. I know they're being changed as the sortDescriptors work and the table organises itself according to the new data but while still displaying the old values. I'm guessing this is down to the recycling of the NSCell's that display the data: although the underlying values have been changed in the Core Data DB they're not re-drawing.

通过 [myArrayController willChangeValueFor:aKeyPath] 和相应的 didChange 尝试各种KVO通知后, code> [myTable reloadData] 。我唯一的解决方案是解开控制器的managedObjectContext绑定,并在处理后重新挂钩,如下所示:

After trying various KVO notifications with [myArrayController willChangeValueFor: aKeyPath] and the corresponding didChange as well as simply [myTable reloadData]. My only solution has been to unhook the managedObjectContext binding of the controller, and re-hook it after processing, like this:

self.hasBackgroundOp = YES;
self.isCancelled = NO; //can get changed with a 'cancel' button in the UI
    if (self.managedObjectContext.hasChanges) {
        [self. managedObjectContext save:nil];
    }
    [myArrayController setManagedObjectContext:nil]; //brutal un-hooking of controller
    dispatch_group_t dispatchGroup = dispatch_group_create();
    dispatch_group_async(dispatchGroup, dispatch_get_global_queue(0, 0), ^{
        .
        .
        // create a thread context, set the persistent store co-ord
        // and do some processing on the
        // NSManagedObjects that are fetched into an array just
        // for the purpose of this thread
        .
        .
        [ctx save:&error];
        //and after the processing is finished then refresh the table
        dispatch_async(dispatch_get_main_queue(), ^{
            [myArrayController setManagedObjectContext:self.managedObjectContext]; //this forces re-drawing of the table
            self.hasBackgroundOp = NO;
            self.isCancelled = NO;
        });
    });

这样看起来真的很残酷 [myArrayController setManagedObjectContext:nil]; ,然后再次设置它只刷新表的内容。我只是不能相信我做了这个正确,虽然它的工作很好。任何人都可以提出更好的方法吗?谢谢!

This seems really brutal to be doing [myArrayController setManagedObjectContext:nil]; and then setting it again just to refresh the table's contents. I just can't believe I've done this correctly although it works just fine. Could anyone advise of a better way? Thanks!

UPDATE:实际设置托管对象上下文不能解决问题。它似乎已停止工作。如果代码在一行中运行两次,那么应用程序只是挂起。注释掉 -setManagedObjectContext:行,代码可以根据需要运行多次。

UPDATE: actually setting the managed object context doesn't solve the problem. It seems to have stopped working. If the code is run twice in a row then the app just hangs. Comment out the -setManagedObjectContext: lines and the code can be run as many times as required.

响应我的自定义单元格使用以下显示自己:

In response to the comments, my custom cell uses the following to display itself:

NSInteger index = [[self stringValue] integerValue] + 1;
NSAttributedString *cellText = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%lu",index] attributes:attributes];
NSRect textRect;
textRect.origin = cellFrame.origin;
textRect.origin.x += (cellFrame.size.width - cellText.size.width) / 2;
textRect.origin.y += (cellFrame.size.height - cellText.size.height) / 2;
textRect.size.width = cellText.size.width;
textRect.size.height = cellText.size.height;
[cellText drawInRect:textRect];

数组控制器在主nib中设置,并且它的托管对象上下文绑定到AppDelegate。在nib中没有获取请求或谓词 - 一个排序描述符在AppDelegate的代码中绑定:

The array controller is setup in the main nib and has it's managed object context bound to the AppDelegate's. There are no fetch requests or predicates in the nib - a sort descriptor is bound in the AppDelegate's code:

[myArrayController setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:kINDEX ascending:YES]]];

推荐答案

想想我发现了 - 我在线程处理并在主线程上执行它:

Think I've found it - I added the following to the end of the threaded processing and executed it on the main thread:

[self.managedObjectContext reset];
[myArrayController fetch:self];

重置MOC显然会清除它,从而强制控制器重绘单元格。 -fetch 似乎是必要的,否则表将变为空白...

Resetting the MOC apparently clears it so forcing the controller to redraw the cells. The -fetch appears to be necessary otherwise the table goes blank...

这篇关于更正Core Data应用程序中的NSTableView的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆