【问题标题】:Can NSTableView column bound to coredata Entity NSArrayController in secondary thread work?NSTableView 列可以绑定到辅助线程中的核心数据实体 NSArrayController 吗?
【发布时间】:2012-12-01 18:26:27
【问题描述】:

我的程序使用 Coredata (SQLite)、NSPersistentDocument、NSTableView 和一个(实体)NSArrayController。我想让主线程中的 NSTableView 列绑定到我在辅助线程中填充的实体 NSArrayController。

问题1:有可能吗?不幸的是,在我的情况下不起作用(虽然通过 IB 在同一个线程中做所有事情)

目标是什么:让“获取”(大文档平均需要 2-4 秒才能完成)在辅助线程中运行,这样我就可以在获取时在 UI 上显示进度指示器。

问题 2:在实体 nsarraycontroller 安排其数据、获取等时,还有其他推荐的方式来显示进度指示器吗?

提前致谢。 路易斯

// ------- ABCoredataController.h
@interface ABCoredataController : NSObject {
:
    NSArrayController               *ivArrayController;
}
@property (nonatomic, assign) NSArrayController  *arrayController;


// ------- ABCoredataController.m

// This piece executes in Main thread... 
- (void) init {
    ivArrayController = [[NSArrayController alloc] init];
:


// Following is later executed in the Secondary Thread
- (void) secondaryThreadRun:(id)param {
    :
    // prepare everything to access coredata from a secondary thread...
    [self setSecondaryThreadMOC: [[[NSManagedObjectContext alloc]init] autorelease] ];
    [[self secondaryThreadMOC] setPersistentStoreCoordinator:[self mainThreadPSC]];

    // prepare the (entity) array controller
    [[self arrayController] setAvoidsEmptySelection:YES];
    [[self arrayController] setPreservesSelection:YES];
    [[self arrayController] setSelectsInsertedObjects:YES];
    [[self arrayController] setClearsFilterPredicateOnInsertion:YES];
    [[self arrayController] setAutomaticallyPreparesContent:YES];
    [[self arrayController] setAutomaticallyRearrangesObjects:YES];
    [[self arrayController] setAlwaysUsesMultipleValuesMarker:NO];
    [[self arrayController] setUsesLazyFetching:NO];
    [[self arrayController] setEditable:YES];
    [[self arrayController] setEntityName:@"Transaction"];

    // bind arrayController to the managedObjectContext   
    [[self arrayController] setManagedObjectContext:[self secondaryThreadMOC]];
    [[self arrayController] setFilterPredicate:[self predicate]];

    :

然后在我控制我的 XIB 和所有 UI 的类中......

// ------- ABWindowController.m
:
// Start the secondaryThreadRun in previous class
[[self coredataCtrlTransaction] start];
// Get the pointer to the entity array controller !!! <== HERE!! is it right?
ivOut_CtEn_Transaction = [[self coredataCtrlTransaction]arrayController];

:
// Bind that entity array controller to the NSTableView columns...
if ( [self out_CtEn_Transaction] != nil ) {
    for ( NSTableColumn *column in [[self out_Tableview_Transaction] tableColumns] ) {
        if ( [column identifier] != nil ) {
            if ( [column infoForBinding:@"value"] == nil ) {
                NSString *theKeyPath=nil;
                if ( [[column identifier] length] > 4 )
                    theKeyPath = [[column identifier] substringFromIndex:4];
                else
                    theKeyPath = [column identifier];

                [column bind: @"value" toObject: [self out_CtEn_Transaction]
                 withKeyPath:[NSString stringWithFormat:@"arrangedObjects.%@", theKeyPath] options:nil];
            }
        }
    }
}

【问题讨论】:

    标签: objective-c cocoa core-data nstableview nsthread


    【解决方案1】:

    回答自己,我发现 KVO 对线程间通信没有好处,我在 MainThread 中设置了观察者,但是在发起键值更改的线程上接收到观察结果(nsarraycontroller 所在的辅助线程)。

    所以,如果我的后台线程更改了一个值,我的后台线程将收到关于它的 KVO。这是我不想要的。

    Found good comment about it here:

    我找到了另一种实现目标的方法,更简单。

    在 GDC herehere 上找到了很好的例子

    我的目标是:让我在“nsarraycontroller 正在获取或排列对象”时展示一个旋转的轮子,在我的情况下这意味着 2-3 秒。

        // Last step in the preparation of the predicate
        NSPredicate  *predicadoFinal = nil;
        predicadoFinal = [NSCompoundPredicate andPredicateWithSubpredicates:array_AND_Total];
    
        // Use GCD (Grand Central Dispatch) to be able to show the spinning wheel
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                // Do here my stuff of showing in the UI something... 
                [[self out_ABSpinning_DDBB] setHidden:NO];
                [[self out_ABSpinning_DDBB] startAnimation:self];
            });
            // And here CPU consuming stuff. 
            // Apply the predicate to the nsarraycontroller. 
            // As the controller has both setAutomaticallyPreparesContent:YES
            // and setAutomaticallyRearrangesObjects:YES so setting 
            // the predicate will automatically trigger the controller
            // to process the predicate and fetch again... 
            [self setPredicateFINAL:predicadoFinal];
        });
    

    如何停止纺车。这也很简单,我在实体 NSArrayController 上设置了一个观察者,如下所示:

    if (nil == ivObservableKeysABCtEn_Transaction ) {
        ivObservableKeysABCtEn_Transaction = [[NSSet alloc] initWithObjects:
                                              @"arrangedObjects",
                                              nil];
    }
    :
    
    if ( [self out_CtEn_Transaction] != nil ) {
    
        for (NSString *keyPath in [self observableKeysABCtEn_Transaction]) {
    
            // Añado observers para cada uno de los keyPaths en los que estoy interesado
            [[self out_CtEn_Transaction] addObserver:self
                         forKeyPath:keyPath
                            options:0
                            context:ABObserverABCtEn_Transaction];
        }
    }
    

    然后在:

    - (void)observeValueForKeyPath:(NSString *)keyPath
                          ofObject:(id)object
                            change:(NSDictionary *)change
                           context:(void *)context
    {
        // Fetch del objeto que ha cambiado en el emisor. En mi caso un BOOL
        id newChange = [change objectForKey:NSKeyValueChangeNewKey];
    
        // Detect null's
        if ([NSNull null] == (NSNull*)newChange) {
            newChange = nil;
        } else {
        :
            //
            // Somthing has changed in the "arrangedObjects" property
            // of my coredata array controller, so it has definitely
            // finished doing its work. 
            if ( context == ABObserverABCtEn_Transaction ) {
               [[self out_ABSpinning_DDBB] stopAnimation:self];
               [[self out_ABSpinning_DDBB] setHidden:YES];
    

    谢谢 路易斯

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多