0

私のアプリでは、次に表示するアイテムを確認する次の方法があります。

- (void)displayIfPossible:(NSNumber *)orderId {
    NSParameterAssert(orderId);
    NSLog(@"displayIfPossible orderId:%@", [orderId stringValue]);

    ItemStore *itemStore = [ItemStore sharedInstance];
    Item *currentItem = [itemStore getItemByOrderId:orderId];

    if (!currentItem) {
        NSLog(@"Fetching next(): currentItem doens't exist");
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [itemStore fetchItemsForFeed:^{
                // TODO FIXME figure out why there's infinite recursion here
                // TEMP FIX: run app once, fetch, stop run again.
                [self displayIfPossible:orderId];
            } withFailureBlock:^{
                [self updateStatus:@"Failed to fetch new items"];
            }];
        });
        return;
    }

    self.item = currentItem;
}

currentItem が存在しない場合、fetchItems はサーバーにクエリを実行し、コア データに永続化します。fetchItems が終了すると、displayIfPossible になるコールバックが再度実行されます。

これはfetchItemsです

- (void)fetchItems:(void (^)(void))callback
  withFailureBlock:(void (^)(void))failureBlock
       withRequestPath:(NSString *)path
            withStatus:(NSNumber *)status {
    APIClient *client = [APIClient sharedManager];
    NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:path parameters:nil];

    AFJSONRequestOperation *operation = \
    [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {

        // Create a new managed object context and set its persistent store coordinator
        // Note that this **must** be done here because this context belongs to another thread
        AppDelegate *theDelegate = [[UIApplication sharedApplication] delegate];
        NSManagedObjectContext *localContext = [[NSManagedObjectContext alloc] init];
        [localContext setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]];

        for (id itemJson in JSON) {
            Item *item = [[ItemStore sharedInstance] getItemByCid:NULL_TO_NIL([itemJson valueForKey:@"id"])];
            if (item == nil) {
                Item *newItem = [NSEntityDescription insertNewObjectForEntityForName:@"Item" \
                                                              inManagedObjectContext:localContext];
                newItem.cid = NULL_TO_NIL([itemJson valueForKey:@"id"]);
                newItem.title = NULL_TO_NIL([itemJson valueForKey:@"title"]);
                newItem.url = NULL_TO_NIL([itemJson valueForKey:@"url"]);
                newItem.image_url = NULL_TO_NIL([itemJson valueForKey:@"image_url"]);
                newItem.order_id = @([[self largestOrderId] intValue] + 1);
                newItem.status = status;

                NSError *error;
                if (![localContext save:&error]) {
                    NSLog(@"Error saving: %@", [error localizedDescription]);
                } else {
                    NSLog(@"fetchItems persisting item cid:%@ order_id:%@", newItem.cid, newItem.order_id);
                }
            }
        }

        if (callback != nil) {
            callback();
        }
    } failure:^(NSURLRequest *request , NSURLResponse *response , NSError *error , id JSON) {
        if (failureBlock) {
            failureBlock();
        }
        NSLog(@"[ItemStore fetchItems] failed. error:%@ response:%@ JSON:%@",
              [error localizedDescription], response, JSON);
    }];

    [operation start];
}

したがって、現在、ここで無限再帰が見られます。

2013-02-18 12:10:07.013 Giordano.iPhone[5946:c07] Unknown class Lik in Interface Builder file.
2013-02-18 12:10:07.040 Giordano.iPhone[5946:c07] displayIfPossible orderId:0
2013-02-18 12:10:07.041 Giordano.iPhone[5946:c07] Fetching next(): currentItem doens't exist
2013-02-18 12:10:07.483 Giordano.iPhone[5946:c07] displayIfPossible orderId:0
2013-02-18 12:10:07.484 Giordano.iPhone[5946:c07] Fetching next(): currentItem doens't exist
2013-02-18 12:10:07.885 Giordano.iPhone[5946:c07] displayIfPossible orderId:0
2013-02-18 12:10:07.886 Giordano.iPhone[5946:c07] Fetching next(): currentItem doens't exist
2013-02-18 12:10:08.325 Giordano.iPhone[5946:c07] displayIfPossible orderId:0
2013-02-18 12:10:08.326 Giordano.iPhone[5946:c07] Fetching next(): currentItem doens't exist
2013-02-18 12:10:08.762 Giordano.iPhone[5946:c07] displayIfPossible orderId:0
2013-02-18 12:10:08.763 Giordano.iPhone[5946:c07] Fetching next(): currentItem doens't exist
2013-02-18 12:10:09.169 Giordano.iPhone[5946:c07] displayIfPossible orderId:0
2013-02-18 12:10:09.170 Giordano.iPhone[5946:c07] Fetching next(): currentItem doens't exist
2013-02-18 12:10:09.614 Giordano.iPhone[5946:c07] displayIfPossible orderId:0
2013-02-18 12:10:09.615 Giordano.iPhone[5946:c07] Fetching next(): currentItem doens't exist
2013-02-18 12:10:10.116 Giordano.iPhone[5946:c07] displayIfPossible orderId:0
2013-02-18 12:10:10.116 Giordano.iPhone[5946:c07] Fetching next(): currentItem doens't exist
2013-02-18 12:10:10.654 Giordano.iPhone[5946:c07] displayIfPossible orderId:0

sqlite データベースを開くと、アイテムが実際にデータベースに挿入されていることがわかります。

マルチスレッドと Core Data が扱いにくいことは承知しており、Apple の同時実行性とコア データに関するドキュメントで概説されている原則に従っていると思います。

displayIfPossible が正しいものを表示しない理由はありますか?

編集

getItemByOrderId のコード

// Returns a newly generated managedObjectContext. Use it for cases without concurrency.

- (NSManagedObjectContext *)managedObjectContext {
    return [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}

- (Item *)getItemByPredicate:(NSPredicate *)predicate {
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item"
                                              inManagedObjectContext:[self managedObjectContext]];
    [request setEntity:entity];
    [request setResultType:NSManagedObjectResultType];
    [request setFetchLimit:1];

    NSSortDescriptor *d = [[NSSortDescriptor alloc] initWithKey:@"order_id" ascending:YES
                                                       selector:nil];
    [request setSortDescriptors:[NSArray arrayWithObject:d]];
    [request setPredicate:predicate];

    Item *ret = nil;
    NSError *error;
    NSArray *objects = [[self managedObjectContext] executeFetchRequest:request error:&error];
    if (objects == nil) {
        // handle the error
    } else {
        if ([objects count] > 0) {
            ret = (Item *)[objects objectAtIndex:0];
        } else if ([objects count] > 1) {
            [NSException raise:@"Duplicated results in core data" format:@"%@", predicate];
        }
    }
    return ret;
}

- (Item *)getItemByOrderId:(NSNumber *)orderId {
    NSParameterAssert(orderId);
    return [self getItemByPredicate:[NSPredicate predicateWithFormat:@"order_id = %@", orderId]];
}
4

2 に答える 2

0

バグが多すぎるのでMRを落としました。

于 2013-02-26T00:00:29.930 に答える