0

私はセルベースのコンテンツモードで標準の NSTableView を持っています。これは dataSource であり、AppDelegate の managedObjectContext に接続された配列コントローラーです。デリゲートでは、このコードはバックグラウンド スレッドのオブジェクトを削除します (db には 30,000 個以上のオブジェクトを含めることができるため、レスポンシブ UI とプログレス バー、およびキャンセル オプションを用意することをお勧めします)。

-(void)deleteObjects:(NSArray*)objs completionBlock:(void (^)(void))aBlock
{
        [self showCancelButton:YES];
        __block __typeof__(self) blockself = self;
        dispatch_group_t dispatchGroup = dispatch_group_create();
        dispatch_group_async(dispatchGroup, dispatch_get_global_queue(0, 0), ^{
            NSManagedObjectContext *mainContext = [(AppDelegate*)[[NSApplication sharedApplication] delegate] managedObjectContext];
            [objs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                [mainContext deleteObject:obj];
                if ((idx % saveSpace == 0) && (idx > 0)) {
                    dispatch_sync(dispatch_get_main_queue(), ^{
                        NSError *error;
                        [blockself.managedObjectContext save:&error];
                        theProgressOverlay.filesCount -= saveSpace; //
                    });
                }
                if (isCancelled) {
                    *stop = TRUE;
                }
            }];
            NSError *error;
            [mainContext save:&error];
            NSLog(@"delete error: %@",error);
            if (aBlock) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self showCancelButton:NO];
                    aBlock();
                });
            }
        });
}

このメソッドは、次のコードによって呼び出されます。

    NSFetchRequest *toDelFetch = [NSFetchRequest fetchRequestWithEntityName:entity];
    [toDelFetch setIncludesPropertyValues:NO];
    NSError *error;
    NSArray *toDelObjs = [self.managedObjectContext executeFetchRequest:toDelFetch error:&error];
    NSLog(@"Error: %@",error);
    if (!toDelObjs || toDelObjs.count < 1) {
        return FALSE;
    }
    [self deleteObjects:toDelObjs completionBlock:{NSLog(@"Finished");}];

すべて正常に動作しているようです: UI の応答性とキャンセル ボタンは常に機能しますが、時々エラーが発生します:

2012-12-13 19:31:53.352 QS[1399:403] *** Assertion failure in -[NSTableRowData _addRowViewForVisibleRow:withPriorView:], /SourceCache/AppKit/AppKit-1138.51/TableView.subproj/NSTableRowData.m:2484
2012-12-13 19:31:53.353 QS[1399:403] Row 1 should be in the valid visible section
2012-12-13 19:31:53.358 QS[1399:403] (
    0   CoreFoundation                      0x00007fff8b773f56 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff88715d5e objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8b773d8a +[NSException raise:format:arguments:] + 106
    3   Foundation                          0x00007fff8db1a71f -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 169
    4   AppKit                              0x00007fff917c6003 -[NSTableRowData _addRowViewForVisibleRow:withPriorView:] + 164
    5   AppKit                              0x00007fff917c5ef2 -[NSTableRowData _addRowViewForVisibleRow:withPriorRowIndex:inDictionary:withRowAnimation:] + 184
    6   AppKit                              0x00007fff917c5e38 -[NSTableRowData _addRowViewForVisibleRow:] + 38
    7   AppKit                              0x00007fff917c557c -[NSTableRowData _unsafeUpdateVisibleRowEntries] + 448
    8   AppKit                              0x00007fff917c5397 -[NSTableRowData updateVisibleRowViews] + 95
    9   AppKit                              0x00007fff9175d854 -[NSTableView viewWillDraw] + 156
    10  AppKit                              0x00007fff916c1f08 -[NSView viewWillDraw] + 666
    11  AppKit                              0x00007fff916c1f08 -[NSView viewWillDraw] + 666
    12  AppKit                              0x00007fff916c2796 -[NSScrollView viewWillDraw] + 43
    13  AppKit                              0x00007fff916c1f08 -[NSView viewWillDraw] + 666
    14  AppKit                              0x00007fff916c1f08 -[NSView viewWillDraw] + 666
    15  AppKit                              0x00007fff916c0c4d -[NSView _sendViewWillDrawInRect:clipRootView:suppressRecursion:] + 1358
    16  AppKit                              0x00007fff916bf9b8 -[NSView displayIfNeeded] + 1039
    17  AppKit                              0x00007fff916bf375 _handleWindowNeedsDisplayOrLayoutOrUpdateConstraints + 648
    18  CoreFoundation                      0x00007fff8b7338e7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    19  CoreFoundation                      0x00007fff8b733846 __CFRunLoopDoObservers + 374
    20  CoreFoundation                      0x00007fff8b708af9 __CFRunLoopRun + 825
    21  CoreFoundation                      0x00007fff8b708486 CFRunLoopRunSpecific + 230
    22  HIToolbox                           0x00007fff8cb352bf RunCurrentEventLoopInMode + 277
    23  HIToolbox                           0x00007fff8cb3c4bf ReceiveNextEventCommon + 181
    24  HIToolbox                           0x00007fff8cb3c3fa BlockUntilNextEventMatchingListInMode + 62
    25  AppKit                              0x00007fff91683779 _DPSNextEvent + 659
    26  AppKit                              0x00007fff9168307d -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 135
    27  AppKit                              0x00007fff9167f9b9 -[NSApplication run] + 470
    28  AppKit                              0x00007fff918fbeac NSApplicationMain + 867
    29  QuickSlide                          0x00000001000019c2 main + 34
    30  QuickSlide                          0x0000000100001994 start + 52

私たちの親愛なる友人である Google で検索するとRow 1 should be in the valid visible section、NSTableView の呼び出しが-reloadData「早すぎる」場合、つまり-awakeFromNib. しかし、私の場合はそうではありません。削除は、アプリが完全に起動した後に確実に行われます。showCancelButton:また、それが私のカスタム進行状況バーではないことを確認するためにコメントアウトし、試してみました

[contentArrayController setAutomaticallyRearrangesObjects:NO];

このアサートを回避するための狡猾なトリックがあるかどうか、誰か教えてもらえますか? それともそれが問題だとしても?アプリは問題なく継続しているようですが、私が見たブログの 1 つは、後で問題を解決していると述べていましたが、詳しくは説明しませんでした。エラーがスローされた後、テーブルの更新が遅くなるようです。

4

1 に答える 1

0

私はそれを理解したと思います。約 1 週間後、私は問題を抱えていませんでした.S * d の法則は、おそらくすべてが再び始まることを意味します.私は自分の質問に答えました.

とにかく、私はデリゲートメソッドを使用していました:

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex

- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView

CD DB の NSManagedObjects でキャッシュされた NSArray を介して、必要に応じてテーブルに値が入力されているように見えました。

ほとんどの場合、オブジェクトを削除するときにエラーが発生しました(思ったにもかかわらず、NSFetchRequestで配列キャッシュを更新しました)。

そこで、ストローのような方法で、各テーブル列で NSTextFieldCell をサブクラス化し、メインの nib ファイルで NSTableColumns を配列コントローラーにバインドすることにしました。これは驚くほどうまくいき、表の行にカーソルを合わせたときのツールチップに関する利点が追加されました。とにかく、言うよりも多くの木材に触れると、すべてが落ち着いたように見えます..... いつでも変更された場合は、この回答を更新します.

更新: NSTableView および/またはマルチスレッドは、UI API とうまく調和していないようです。バックグラウンド スレッドから戻ると、NSDrawers やシートなどはアニメーション化されないことがわかりました。-orderOut や -toggle などの標準メソッドは無視されます。上記と遅延アニメーション (遅延後にセレクターを実行) を使用して NSView を使用すると、アプリが完全に落ち着いたようです。

于 2012-12-21T12:17:37.620 に答える