0

いくつかの CoreData オブジェクトにロードする NSFetchedResultsController を含むテーブルビューをアプリに持っています。

テーブルが に組み込まれcellForRowAtIndexPath:ているため、セルごとにフェッチを実行して、別のオブジェクトから他の情報を取得する必要があります。

テーブルは UserTasks で満たされているため、UserSite から情報を取得する必要があります (UserTask には siteID 属性が含まれています)。

バックグラウンド スレッドで UserSite 情報を取得し、一時的なコンテキストを使用しています。正常に動作しますが、スクロール時に UI を少し遅らせたいと考えています。

        Site *site = [_scannedSites objectForKey:task.siteID];
        if(!site)
        {   
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

                AppDelegate *ad = [AppDelegate sharedAppDelegate];
                NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
                temporaryContext.persistentStoreCoordinator = ad.persistentStoreCoordinator;

                Site *site2 = [task getSiteWithContext:temporaryContext];
                if(site2)
                {
                    [ad.managedObjectContext performBlock:^{

                        Site *mainContextObject = (Site *)[ad.managedObjectContext objectWithID:site2.objectID];
                        [_scannedSites mainContextObject forKey:task.siteID];
                    }];
                    dispatch_async(dispatch_get_main_queue(), ^{
                        Site *newSite = [_scannedSites objectForKey:task.siteID];
                        cell.lblCustName.text = newSite.siteName;
                        cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", newSite.siteAddressLine1, newSite.siteCity, newSite.siteState];
                        cell.lblPhone.text = [self formatPhoneNum:newSite.phone];
                    });
                }
                else
                {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        cell.lblCustName.text = @"";
                        cell.lblAddr.text = @"";
                        cell.lblPhone.text = @"";
                    });
                }
            });
        }
        else
        {
            cell.lblCustName.text = site.siteName;
            cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", site.siteAddressLine1, site.siteCity, site.siteState];
            cell.lblPhone.text = [self formatPhoneNum:site.phone];
        }    

ご覧のとおり、タスクの UserSite 情報が にまだない場合は_scannedSites、バックグラウンド スレッドが開始され、そのタスクの UserSite が取得されて保存され、メイン スレッドで詳細が入力されます。

私が言ったように、スクロールするときにかなり迷惑なラグがあります...バックグラウンドで作業を行うことで回避したかったのです。

私はこれについて間違った方法で進んでいますか?

ありがとう、アドバイスをいただければ幸いです。


編集 CoreData でリレーションシップを作成し、現在それを使用していcellForRowAtIndexPathます。まだ存在しない場合は、作成します。これははるかにうまく機能しています。

    Site *site = task.site;
    if(!site)
    {
        AppDelegate *ad = [AppDelegate sharedAppDelegate];
        NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        temporaryContext.persistentStoreCoordinator = ad.persistentStoreCoordinator;

        [temporaryContext performBlock:^{

            Site *tempContextSite = [task getSiteWithContext:temporaryContext];

            [ad.managedObjectContext performBlock:^{
                Site *mainManagedObject = (Site *)[ad.managedObjectContext objectWithID:tempContextSite.objectID];
                task.site = mainManagedObject;
                NSError *error;
                if (![temporaryContext save:&error])
                {
                }
                [ad.managedObjectContext performBlock:^{
                    NSError *e = nil;
                    if (![ad.managedObjectContext save:&e])
                    {

                    }
                    dispatch_async(dispatch_get_main_queue(), ^{
                        cell.lblCustName.text = mainManagedObject.siteName;
                        cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", mainManagedObject.siteAddressLine1, mainManagedObject.siteCity, mainManagedObject.siteState];
                        cell.lblPhone.text = [self formatPhoneNum:mainManagedObject.phone];
                    });
                }];
            }];
        }];
    }
    else
    {
        cell.lblCustName.text = site.siteName;
        cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", site.siteAddressLine1, site.siteCity, site.siteState];
        cell.lblPhone.text = [self formatPhoneNum:site.phone];
    }
4

2 に答える 2

1

UserTaskに関連する場合UserSite、通常の Core Data のアプローチは、2 つの間の関係を作成し、実行時にその関係を使用することです。したがって、UserTaskという名前のプロパティがありsite、特定のインスタンスにそのプロパティの値を尋ねるだけです。ID 属性はまだ存在する可能性がありますが、外部データ ストア (サーバー API など) と同期する場合にのみ使用されます。

このような ID の保存とオブジェクトの検索は、実行時に多くの不要な作業を行うように設計された、基本的に厄介なアプローチです。Core Data が提供しようとするすべての便利さを回避し、代わりに困難な方法を実行します。テーブルのスクロール中にこの作業を行うのも、パフォーマンスの問題が最も顕著になるため、最悪の場合です。

何らかの理由でこのようにする必要があるUserSite場合は、テーブルがスクロールしている間ではなく、事前にすべてのインスタンスを検索することで最適化できます。すべてのインスタンスがわかっているUserTask場合は、ビューが読み込まれるときに 1 回の呼び出しですべてのサイトを取得します。

于 2013-05-03T18:37:10.567 に答える
1

で非同期タスクを送信するのは悪い考えですcellForRowAtIndexPath:。ユーザーがスクロールすると、不要なスレッドが大量に作成されます。

必要な情報をフェッチし、必要に応じて更新するように UI に通知するバックグラウンド プロセスを用意する方がはるかに優れています。これはかなり標準的なものであり、堅実な実装の多くの例を簡単に見つけることができます。

于 2013-05-03T18:40:01.740 に答える