在我的应用程序中,我有以下方法来检查下一个要显示的项目,
- (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]];
}