1

私は AFNetworking と MagicalRecord (現在の開発ブランチ) を使用しており、互いに依存している多くのオブジェクトをインポートする方法を見つけようとしています。各リソース/エンティティには、ダウンロードに相当する複数のページがあります。特定のエンティティのダウンロードを管理し、MagicalDataImport を使用してそれらを保存するクラスがあります (これは驚くべきことです)。

私の問題は、インポートが同じスレッドで行われていないことだと思います。だから私は何が起こっていると思います:

  • 1 つのスレッドで、EntityA が適切に保存され、親エンティティに伝達されます。
  • 次に、別のスレッドで EntityB が保存され、それに伴い EntityA との関係が構築されます。これは、空の (障害?) オブジェクトが作成されていることを意味します。次に、それが親エンティティに伝播されると、EntityA がそこにある EntityA を上書きしていると思います。したがって、すべての属性を持たないオブジェクトがいくつか残っています。

少なくとも、それが起こっていると思います。UI を介して私が見ているのは、エンティティ間の関係が常に正しく構築されていないということです。

私の最終的な目標は、UI にまったく影響を与えずに、ダウンロード/インポート プロセス全体をバックグラウンドで実行することです。

ここに私の AFJSONRequest があります:

AFJSONRequestOperation *operation = [AFJSONRequestOperation
     JSONRequestOperationWithRequest:request
     success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
     {
         [self saveResources:[JSON objectForKey:@"data"]];
     }
     failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON)
     {
         DLog(@"%@",error.userInfo);
         [self.webService command:self didFail:error.localizedDescription];
     }];

[operation setQueuePriority:self.priority];

そしてそれは呼び出しますsaveResources:

- (void)saveResources:(NSArray*)resources {
    BOOL stopDownloads = [self stopDownloadsBasedOnDate:resources];
    if ([resources count] > 0 && !stopDownloads){
        self.offset = @([offset intValue] + [resources count]);
        [self send];
    }

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *blockLocalContext) {
        [self.classRef MR_importFromArray:resources inContext:blockLocalContext];
    } completion:^(BOOL success, NSError *error) {
        if (error){
            // ... handle errors
        }
        else {
            // ... handle callbacks
        }
    }];
}

これにより、別のダウンロード ( [self send]) が開始され、オブジェクトが保存されます。

デフォルトでは、AFNetworking がメイン キューでコールバックを呼び出すことはわかっています。また、SuccessCallbackQueue/FailureCallbackQueueをバックグラウンド スレッドに設定しようとしましたが、すべての問題が解決するわけではないようです。すべてをバックグラウンド スレッドで実行し続けるには、そうする必要があると思います。

これらの変更をメイン コンテキストに適切に伝達するために、他に呼び出す必要があるものはありますか? または、すべてのオブジェクトが正しく保存され、関係が適切に構築されていることを確認するために、これを設定する必要がある別の方法はありますか?

更新 問題をより明確にするために、問題を書き直しました。

アップデート

さらにコードが必要な場合は、(私が信じている) すべての要点を作成しました。

4

2 に答える 2

1

これがあなたの問題かどうかは100%わかりませんが、これを答えにしています。問題は localContext に起因すると思います。これは、データのインポートを使用する、私たちが作成したアプリのサンプル Web リクエスト メソッドです。これを例として使用して、自分のアプリを機能させることができる場合があります。

AFNetworking がメイン スレッドで完了ブロックを実行し、次に MagicalRecord saveInBackground メソッドがバックグラウンド スレッドに戻ってインポートと処理を実行し、最後の MR 完了ブロックが再びメイン スレッドでハンドラー ブロックを実行することに注意してください。インポートに使用される localContext は、saveInBackground メソッドによって作成/管理されます。そのメソッドが完了すると、コンテキストが保存され、アプリのメイン コンテキストとマージされ、すべてのデータにアクセスできるようになります。

- (void)listWithCompletionHandler:(void (^)(BOOL success))handler{
    [[MyAPIClient sharedClient] getPath:@"list.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject){
        NSString *statusString = [responseObject objectForKey:@"status"];

        // Handle an error response
        if(![statusString isKindOfClass:[NSString class]] || ![statusString isEqualToString:@"success"]){
            // Request failure
            NSLog(@"List Request Error: %@", statusString);
            NSLog(@"%@", [responseObject objectForKey:@"message"]);
            if(handler)
                handler(NO);
            return;
        }

        NSArray *itemsArray = [responseObject objectForKey:@"items"];

        [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
            // Load into internal database
            NSArray *fetchedItems = [Item importFromArray:itemsArray inContext:localContext];

            NSLog(@"Loaded %d Items", [fetchedItems count]);
        } completion:^{
            if(handler)
                handler(YES);
        }];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error){
        NSLog(@"Fail: %@", error);
        if(handler)
            handler(NO);
    }];
}
于 2013-09-05T22:57:19.713 に答える