在我的应用中,我有以下方法来检查要显示的下一个项目,
- (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将查询服务器并持久存入Core Data。当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数据库,我可以看到项目确实已插入到数据库中。
我知道多线程和核心数据可能很棘手,我认为我已遵循Apple与核心数据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]];
}
答案 0 :(得分:2)
上下文不知道其他上下文中的更改,除非它们是从子上下文推送到它的。在您的情况下,您应该从执行保存到持久存储和合并更改的上下文中侦听NSManagedObjectContextDidSaveNotification
。另一种方法是在你的NSOperation中产生一个子上下文,它会在fetch完成时将更改推送到它的父级(用于显示项目的那个),但这完全取决于你并依赖于应用程序设计。
答案 1 :(得分:0)
我放弃了MR,因为它太多了。