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's concurrency with core data doc 概述的原则。

任何想法为什么 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

2

上下文不知道其他上下文中的更改,除非它们是从子上下文推送到它的。在您的情况下,您应该从执行保存到持久存储和合并更改的上下文中收听NSManagedObjectContextDidSaveNotification。另一种方法是在您的 NSOperation 中生成一个子上下文,当 fetch 完成时,它会将更改推送到它的父级(用于显示项目的那个),但这完全取决于您并且取决于应用程序设计。

于 2013-02-18T21:29:23.727 回答
0

我放弃了 MR,因为它太麻烦了。

于 2013-02-26T00:00:29.930 回答