2

私たちのテーブル ビュー コントローラーは、NSFetchedResultsControllerコア データからのデータを表示するために を使用します。バックグラウンドで新しいデータをダウンロードします。エンティティが新しいデータで変更されると、iOS 5.1.1 電話では、更新ではなくテーブルの新しい行として扱われます。iOS 5.1 シミュレーターまたは iOS 6 デバイスでは複製できません。

は、 with 同時実行タイプUIApplicationDelegateを作成します。私たちの道具。新しいデータを取得します。データを取得するメソッドでは、並行 Typeで秒を作成します。その新しいコンテキストでa を実行し、ネットワーク呼び出しと json 解析を実行します。以前のデータを取得するための があるため、古いオブジェクトを削除したり、同じ ID を持つ既存のエンティティを変更したりできます。既存のエンティティを変更するか、新しいエンティティを作成した後、古いエンティティ オブジェクトを削除します。次に、このプライベート コンテキストを保存します。次に、親コンテキストで aを実行して、そこに変更を保存します。NSManagedObjectContextNSMainQueueConcurrencyTypeUITableViewControllerNSFetchedResultsControllerDelegateviewWillAppearNSManagedObjectContextNSPrivateQueueConcurrencyTypeperformBlockNSFetchRequestdeleteObjectperformBlock

iOS5.1 では表が正しくありません。オブジェクトを変更すると、変更されるのではなく、新しい行としてテーブルに追加されます。このコントローラを離れて戻ってきて、新しいデータを取得すると、適切な量が表示されます。

AppDelegate.m

- (void)saveContext
{

    [self.privateWriterContext performBlock:^{
        NSError *error = nil;
        [self.privateWriterContext save:&error];
        // Handle error...
        [[NSNotificationCenter defaultCenter] removeObserver:self     name:NSManagedObjectContextDidSaveNotification object:self.privateWriterContext];
    }];
}

#pragma mark - Core Data stack

- (NSManagedObjectContext *)privateWriterContext
{
    if (__privateWriterContext != nil) {
        return __privateWriterContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        __privateWriterContext = [[NSManagedObjectContext alloc]     initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [__privateWriterContext setPersistentStoreCoordinator:coordinator];
    }
    return __privateWriterContext;
}

- (NSManagedObjectContext *)managedObjectContext
{
    if (__managedObjectContext != nil) {
        return __managedObjectContext;
    }

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        __managedObjectContext = [[NSManagedObjectContext alloc]     initWithConcurrencyType:NSMainQueueConcurrencyType];
        [__managedObjectContext setParentContext:self.privateWriterContext];
    }

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(saveContext:)
                                                      name:NSManagedObjectContextDidSaveNotification
                                               object:__managedObjectContext];
    return __managedObjectContext;
}

サーバーからフェッチするクラス

+ (void) fetchFromURL:(NSString *) notificationsUrl withManagedObjectContext (NSManagedObjectContext *)managedObjectContext
{
    NSManagedObjectContext *importContext = [[NSManagedObjectContext alloc]     initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    importContext.parentContext = managedObjectContext;
    [importContext performBlock: ^{

        NSError *error;
        NSURLResponse *response;

        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

        NSData *responseData = [NSData dataWithContentsOfURLUsingCurrentUser:[NSURL URLWithString:notificationsUrl] returningResponse:&response error:&error];

        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        NSMutableSet *newKeys = [[NSMutableSet alloc] init];
        NSArray *notifications;
        if(responseData) {
            NSDictionary* json = [NSJSONSerialization
                                  JSONObjectWithData:responseData
                                  options:kNilOptions
                                  error:&error];

            NSMutableDictionary *previousNotifications = [[NSMutableDictionary alloc] init];
            NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Notification"];

            NSArray * oldObjects = [importContext executeFetchRequest:request error:&error];
            for (Notification* oldObject in oldObjects) {
                [previousNotifications setObject:oldObject forKey:oldObject.notificationId];
            }
            notifications = [json objectForKey:@"notifications"];
            //create/update objects
            for(NSDictionary *notificationDictionary in notifications) {

                NSString *notificationId =  [notificationDictionary objectForKey:@"id"];
                Notification *notification = [previousNotifications objectForKey:notificationId];

                if(notification) {
                    [previousNotifications removeObjectForKey:notificationId];
                } else {
                     notification = [NSEntityDescription insertNewObjectForEntityForName:@"Notification" inManagedObjectContext:importContext];
                     [newKeys addObject:notificationId];
                }
                notification.notificationId = [notificationDictionary objectForKey:@"id"];
                //other properties from the json response

            }

            for (NSManagedObject * oldObject in [previousNotifications allValues]) {
                [importContext deleteObject:oldObject];
            }
        }

        if (![importContext save:&error]) {
            NSLog(@"Could not save to main context after update to notifications: %@", [error userInfo]);
        }

        //persist to store and update fetched result controllers
        [importContext.parentContext performBlock:^{
            NSError *parentError = nil;
            if(![importContext.parentContext save:&parentError]) {
                NSLog(@"Could not save to store after update to notifications: %@", [error userInfo]);
            }
        }];

        }
     ];
}
4

1 に答える 1

1

私も最近その問題に悩まされました。

問題は、異なるスレッドに 2 つのコンテキストがあるためです。

iOS 5.1 を実行しているデバイスでは、それらをマージすると、更新ではなく新しいレコードが挿入されます。代わりにメイン コンテキストを使用するようにバックグラウンド スレッドを変更すると、問題はなくなりました。

この特定のケースでマージが機能しない理由はわかりません。

于 2013-02-22T09:08:47.343 に答える