1

私が開発しているアプリは、API を介して製品カタログ (約 40,000 製品になります) を取得し、それらを CoreData に解析して、簡単に検索できるようにします。

データの解析を処理するこの方法があり、ダウンロードは完全に意図したとおりに機能します。ダウンロード進行状況バーと処理進行状況バーがあります。ダウンロードは必要に応じて機能しますが、ラベル (または進行状況バー) は処理テキストまたは進行状況のパーセンテージに変わりません。プログラムで確認したところ、正しいラベル テキストがコンソールに出力されますが、ビューには表示されません。

アクティビティ モニターを使用して確認したところ、電話は CPU に関して最大​​になっています..そのため、オンビューの変更が表示されていないと思います。計算負荷を減らしてプログレスバーを適切に表示する方法はありますか? とにかく、これは効率的なコードとはほど遠いと確信しています。ベストプラクティスなどを知っている段階にはまだ行っていません..

ループ GCD を使用するように変更

GCD を使用するようにコードを変更しましたが、実行時にエラーが発生します: * キャッチされない例外 'NSGenericException' が原因でアプリを終了しています。 '

- (void) processUpdatesBG {

    NSArray *jsonArray=[NSJSONSerialization JSONObjectWithData:_responseData options:0 error:nil];
    NSArray *products = [jsonArray valueForKey:@"products"];

    NSInteger productDBCount = _productDBCount;
    productDBCount = 0;

    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *managedObjectContext = delegate.managedObjectContext;
    _managedObjectContext = managedObjectContext;

    self.totalCount = [products count];

    for (id product in products) {

        dispatch_queue_t processTheUpdates = dispatch_queue_create("com.app.process_the_updates", 0);



            NSFetchRequest *request = [[NSFetchRequest alloc] init];
            [request setEntity:[NSEntityDescription entityForName:@"Products" inManagedObjectContext:_managedObjectContext]];
            [request setIncludesSubentities:NO];


            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"codes == %@", [product valueForKey:@"product_codes"]];
            [request setPredicate:predicate];



         dispatch_async(processTheUpdates,  ^{
             NSError *err;
             NSArray *results = [_managedObjectContext executeFetchRequest:request error:&err];
            if (results.count == 0){
                // Product doesn't exist with code, make a new product

                NSLog(@"Product.. %@", [product valueForKey:@"product_name"]);

                NSManagedObject* newProduct;
                newProduct = [NSEntityDescription insertNewObjectForEntityForName:@"Products" inManagedObjectContext:_managedObjectContext];

                [newProduct setValue:[product valueForKey:@"product_name"] forKey:@"name"];
                [newProduct setValue:[product valueForKey:@"product_codes"] forKey:@"codes"];

                if ([product valueForKey:@"information"] == (id)[NSNull null]){
                    // No information, NULL
                    [newProduct setValue:@"" forKey:@"information"];
                } else {
                    NSString *information = [product valueForKey:@"information"];
                    [newProduct setValue:information forKey:@"information"];

                }

            } else {

                // Product exists, update existing product
                for (NSManagedObject *r in results) {
                    [r setValue:[product valueForKey:@"product_name"] forKey:@"name"];

                    if ([product valueForKey:@"information"] == (id)[NSNull null]){
                        // No information, NULL
                        [r setValue:@"" forKey:@"information"];
                    } else {
                        NSString *information = [product valueForKey:@"information"];
                        [r setValue:information forKey:@"information"];
                    }

                }


            }

            dispatch_async(dispatch_get_main_queue(), ^{
                self.productDBCount = productDBCount + 1;
                NSNumber *progress = [NSNumber numberWithFloat:(self.productDBCount / self.totalCount)];
                self.downloadUpdateProgress.progress = [progress floatValue];
                NSLog(@"Added product");
            });

        });



    }

    NSError *error;

    if ([self.managedObjectContext save:&error]) {
        NSLog(@"Database Updated");
    } else {
        NSLog(@"Database not Updated, Error: %@", error);
    }


    self.updateStatus.text = @"Update Completed!";
    self.downloadUpdateProgress.hidden = YES;
    self.close.hidden = NO;

    //    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    //    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *now = [[NSDate alloc] init];
    //    NSString *currentTimestamp = [dateFormatter stringFromDate:now];
    //    NSLog(@"%@", currentTimestamp);


    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    NSString *apiUpdateTimestamp = [jsonArray valueForKey:@"last_updated"];
    [prefs setObject:now forKey:@"last_downloaded_update"];
    [prefs setObject:apiUpdateTimestamp forKey:@"api_update_timestamp"];
    [prefs synchronize];
    // Set the lastDownloadedTimestamp as today
    // Set the last

}

オリジナルコード

- (void) processUpdates {
    self.updateStatus.text = @"Processing Updates";
    self.downloadUpdateProgress.progress = 0;

    NSArray *jsonArray=[NSJSONSerialization JSONObjectWithData:_responseData options:0 error:nil];
    NSArray *products = [jsonArray valueForKey:@"products"];

    NSInteger productDBCount = 0; 

    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *managedObjectContext = delegate.managedObjectContext;
    _managedObjectContext = managedObjectContext;

    NSInteger totalCount = [products count];

    for (id product in products) {
        NSFetchRequest *request = [[NSFetchRequest alloc] init];
        [request setEntity:[NSEntityDescription entityForName:@"Products" inManagedObjectContext:_managedObjectContext]];
        [request setIncludesSubentities:NO];
        NSError *err;
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"codes == %@", [product valueForKey:@"product_codes"]];
        [request setPredicate:predicate];

        NSArray *results = [_managedObjectContext executeFetchRequest:request error:&err];

        if (results.count == 0){
        // Product doesn't exist with code, make a new product

            NSManagedObject* newProduct;
            newProduct = [NSEntityDescription insertNewObjectForEntityForName:@"Products" inManagedObjectContext:_managedObjectContext];

            [newProduct setValue:[product valueForKey:@"product_name"] forKey:@"name"];
            [newProduct setValue:[product valueForKey:@"product_codes"] forKey:@"codes"];

            if ([product valueForKey:@"information"] == (id)[NSNull null]){
                // No information, NULL
                [newProduct setValue:@"" forKey:@"information"];
            } else {
                NSString *information = [product valueForKey:@"information"];
                [newProduct setValue:information forKey:@"information"];

            }                  

        } else {

            // Product exists, update existing product
            for (NSManagedObject *r in results) {
                [r setValue:[product valueForKey:@"product_name"] forKey:@"name"];

                if ([product valueForKey:@"information"] == (id)[NSNull null]){
                    // No information, NULL
                    [r setValue:@"" forKey:@"information"];
                } else {
                    NSString *information = [product valueForKey:@"information"];
                    [r setValue:information forKey:@"information"];                    
                }

            }

        }

        productDBCount = productDBCount + 1;
        NSNumber *progress = [NSNumber numberWithFloat:(productDBCount / totalCount)];
        self.downloadUpdateProgress.progress = [progress floatValue];

    }

    NSError *error;

    if ([self.managedObjectContext save:&error]) {
        NSLog(@"Database Updated");        
    } else {
        NSLog(@"Database not Updated, Error: %@", error);
    }


    self.updateStatus.text = @"Update Completed!";
    self.downloadUpdateProgress.hidden = YES;
    self.close.hidden = NO;

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *now = [[NSDate alloc] init];
    NSString *currentTimestamp = [dateFormatter stringFromDate:now];
    NSLog(@"%@", currentTimestamp);


    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    NSString *apiUpdateTimestamp = [jsonArray valueForKey:@"last_updated"];
    [prefs setObject:currentTimestamp forKey:@"last_downloaded_update"];
    [prefs setObject:apiUpdateTimestamp forKey:@"api_update_timestamp"];
    [prefs synchronize];
    // Set the lastDownloadedTimestamp as today
    // Set the last

}
4

3 に答える 3

2

UI 作業用にメイン スレッドを解放するには、複数のスレッドで実行する必要があります。残念ながら、複数のスレッドでの Core Data は簡単ではありません。このリンクは、これを実装する素晴らしい方法を示しています http://www.cocoanetics.com/2012/07/multi-context-coredata/

于 2013-06-12T11:05:36.063 に答える
0

私はこのようなもので行きました。うまくいった例が見つからなかったので、これが将来誰かに役立つことを願っています。非常に基本的ですが、要点を理解できるはずです。これが最終的に私が選んだ解決策です。

dispatch_queue_t backgroundDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

for (id p in products) {

  // Dispatch the following code on our background queue
  dispatch_async(backgroundDispatchQueue,
    ^{
        id product = p;
        // Because at this point we are running in another thread we need to create a
        // new NSManagedContext using the app's persistance store coordinator

        NSManagedObjectContext *backgroundThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
        [backgroundThreadContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];

        /*
        *
        *
        * Perform fetch and other actions as required.
        *
        *
        */

        dispatch_async(dispatch_get_main_queue(), ^
        {

            self.productDBCount = self.productDBCount + 1;
            float progress = ((float)self.productDBCount / (float)self.totalCount);
            int percent = progress * 100.0f;
            self.downloadUpdateProgress.progress = progress;
            self.percentageComplete.text = [NSString stringWithFormat:@"%i", percent];

        });

      });
}
于 2013-06-19T07:22:09.687 に答える