0

私のプログラムは、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];
            }
        }
    }
}
4

1 に答える 1

0

自分自身に答えると、KVOはスレッド間通信には適していないことがわかりました。メインスレッドでオブザーバーを設定していますが、キー値の変更を開始したスレッド(nsarraycontrollerが存在するセカンダリスレッド)でオブザーバーを受信します。

したがって、バックグラウンドスレッドが値を変更すると、バックグラウンドスレッドはそれに関するKVOを受け取ります。それは私が望まないものです。

ここでそれについての良いコメントを見つけました:

私は自分の目的を達成するための別の方法を見つけました。もっと簡単です。

ここここでGDCの非常に良い例を見つけました

私の目的は、「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];

ありがとうルイス

于 2012-12-01T09:22:48.320 に答える