我在uitabbarcontroller中有两个带有三个视图控制器的iPad应用程序。在每个视图控制器中,我调用不同的Web服务并使用RestKit将它们映射到核心数据实体,然后使用nsfetchedresultscontroller在uitableview中显示数据。有关我的实施的更多信息是here。
第一次加载数据时,数据在每个视图控制器上正确加载和映射,但是当我在视图controller-3中加载数据后尝试重新加载视图controller-2中的数据时,在一个视图控制器中应用程序崩溃时出现以下错误:
2015-11-07 00:17:45.205 PharmacyStockTake [193:3854] T restkit.network:RKResponseMapperOperation.m:504将HTTP响应映射到nil目标对象... 2015-11-07 00:17:45.206 PharmacyStockTake [193:3854]我的restkit.core_data:RKInMemoryManagedObjectCache.m:94通过属性'stockTakeLocId'缓存实体'RackStockTakeStatus'的实例 2015-11-07 00:17:45.213 PharmacyStockTake [193:3854] *断言失败 - [RKEntityByAttributeCache addObjects:completion:],/ Users / saif / Documents / iDev / ComPrjs / PharmacyStockTake / Pods / RestKit / Code /CoreData/RKEntityByAttributeCache.m:333 2015-11-07 00:17:45.214 PharmacyStockTake [193:3854] * 由于未捕获的异常'NSInternalInconsistencyException'终止应用程序,原因:'无法添加具有实体'RackStockTakeStatus'的对象来缓存'RackStockTakeStatus'的实体“ ***第一次抛出调用堆栈: (0x2201585b 0x33a5adff 0x22015731 0x22da6ddb 0x14b67b 0x21d9034b 0x21d9022d 0x14b175 0x15a9e1 0x21d9034b 0x21d9022d 0x15a71d 0x161327 0x17bfb9 0x17a769 0x220091e9 0x21f8bbdb 0x17a65b 0x17c21b 0x17c9cd 0x17d271 0x22d283cf 0x1c3925 0x21d9034b 0x422d03 0x42c4fb 0x21d90247 0x1c26bb 0x1c072d 0x22d283cf 0x22dd682d 0x42d61b 0x425f53 0x42eb0f 0x42e961 0x34314e0d 0x343149fc) libc ++ abi.dylib:以NSException类型的未捕获异常终止
这是我的代码:
在AppDelegate中初始化RestKit:
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:baseURL];
//[RKObjectManager setSharedManager:objectManager];
[RKObjectManager setSharedManager:objectManager];
// Initialize managed object model from bundle
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
// Initialize managed object store
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
objectManager.managedObjectStore = managedObjectStore;
// Complete Core Data stack initialization
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"StockTakeDB.sqlite"];
NSString *seedPath = [[NSBundle mainBundle] pathForResource:@"StoreItemsDB" ofType:@"sqlite"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, @"Failed to add persistent store with error: %@", error);
// Create the managed object contexts
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
View-Controller-2中的RestKit初始化和配置代码:
-(void)initTakeStockRestKit
{
takeStockLocationWithStatusRequestPath = @"/stocktake/stocktake/1/usr/1/locwithstatus";
RKObjectManager *objectManager = [RKObjectManager sharedManager];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
// Initialize managed object model from bundle
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
// Initialize managed object store
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
objectManager.managedObjectStore = managedObjectStore;
// Complete Core Data stack initialization
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"StockTakeDB.sqlite"];
NSString *seedPath = [[NSBundle mainBundle] pathForResource:@"StoreItemsDB" ofType:@"sqlite"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, @"Failed to add persistent store with error: %@", error);
// Create the managed object contexts
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[objectManager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) {
RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:takeStockLocationWithStatusRequestPath];
NSDictionary *argsDict = nil;
BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];
if (match) {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"RackStockTakeStatus"];
return fetchRequest;
}
return nil;
}];
RKEntityMapping *rackStockTakeStatusListMapping = [RKEntityMapping mappingForEntityForName:@"RackStockTakeStatus" inManagedObjectStore:managedObjectStore];
rackStockTakeStatusListMapping.identificationAttributes = @[@"stockTakeLocId"];
[rackStockTakeStatusListMapping addAttributeMappingsFromDictionary:
@{
@"stockTakeLocId" : @"stockTakeLocId",
@"stockTakeUuid" : @"stockTakeUuid",
@"locId" : @"locId",
@"locName" : @"locName",
@"status" : @"status",
@"stockTakeByUser" : @"stockTakeByUser",
@"stockTakeByUserId" : @"stockTakeByUserId",
@"beginTime" : @"beginTime",
@"percentCompleted" : @"percentCompleted"
}
];
RKResponseDescriptor *rackStockTakeStatusListResponseDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:rackStockTakeStatusListMapping
method:RKRequestMethodGET
pathPattern:@"/stocktake/stocktake/:id/usr/:id/locwithstatus"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)
];
[objectManager addResponseDescriptor:rackStockTakeStatusListResponseDescriptor];
}
View-Controller-2上的数据加载:
NSString *requestPath = [NSString stringWithFormat:@"/stocktake/stocktake/%@/usr/1/locwithstatus",[defaults objectForKey:@"loggedInUserSelectedStoreId"]];
[[RKObjectManager sharedManager]
getObjectsAtPath:requestPath
parameters:nil
success: ^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSManagedObjectContext *context = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RackStockTakeStatus" inManagedObjectContext:context];
[request setEntity:entity];
NSError *error;
[context executeFetchRequest:request error:&error];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
}
[self.tableView reloadData];
NSLog(@"requestDataItemsForStore - Mapping Success");
}
failure: ^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(@"Load failed with error: %@", error);
NSLog(@"requestDataItemsForStore - Loading Failed");
}
];
View-Controller-3中的RestKit初始化和配置代码:
RKObjectManager *objectManager = [RKObjectManager sharedManager];
// Initialize managed object model from bundle
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
// Initialize managed object store
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
objectManager.managedObjectStore = managedObjectStore;
// Complete Core Data stack initialization
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"StockTakeDB.sqlite"];
NSString *seedPath = [[NSBundle mainBundle] pathForResource:@"StoreItemsDB" ofType:@"sqlite"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, @"Failed to add persistent store with error: %@", error);
// Create the managed object contexts
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[objectManager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) {
RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:itemsByLocationRequestPath];
NSDictionary *argsDict = nil;
BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];
if (match) {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"ItemsByLocation"];
return fetchRequest;
}
return nil;
}];
RKEntityMapping *itemsByLocationListMapping = [RKEntityMapping mappingForEntityForName:@"ItemsByLocation" inManagedObjectStore:managedObjectStore];
itemsByLocationListMapping.identificationAttributes = @[@"itemId"];
[itemsByLocationListMapping addAttributeMappingsFromDictionary:
@{
@"itemId" : @"itemId",
@"itemName" : @"itemName",
@"itemCode" : @"itemCode",
@"uomCode" : @"uomCode",
@"locId" : @"locId",
@"locName" : @"locName",
@"subLocId" : @"subLocId",
@"subLocName" : @"subLocName",
@"storeItemId" : @"storeItemId",
@"stockTakeQtyId" : @"stockTakeQtyId",
@"countedTime" : @"countedTime",
@"countQty" : @"countQty",
@"removed" : @"removed",
@"remarks" : @"remarks"
}
];
RKResponseDescriptor *itemsByLocationListResponseDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:itemsByLocationListMapping
method:RKRequestMethodGET
pathPattern:@"/stocktake/stocktake/:id/loc/:id/usr/:id/items"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)
];
[objectManager addResponseDescriptor:itemsByLocationListResponseDescriptor];
View Controller-3上的数据加载:
[[RKObjectManager sharedManager]
getObjectsAtPath:itemsByLocationRequestPath
parameters:nil
success: ^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSManagedObjectContext *context = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"ItemsByLocation"];
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"subLocName" ascending:YES];
fetchRequest.sortDescriptors = @[descriptor];
NSError *error = nil;
[context executeFetchRequest:fetchRequest error:&error];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
}
[self.tableView reloadData];
NSLog(@"requestDataItemsForStore - Mapping Success");
}
failure: ^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(@"Load failed with error: %@", error);
NSLog(@"requestDataItemsForStore - Loading Failed");
}
];
您能帮忙解决这个问题吗?
答案 0 :(得分:1)
这是一个线程和/或多个上下文问题。您的实体缓存是使用一个上下文设置的,但是您从不同的上下文中使用它(这就是实体具有相同名称但不同的原因)。
这可能是因为您正在设置多个不同的核心数据堆栈(从代码示例中看起来就像这样)。在这种情况下,您应该将所有核心数据堆栈和映射分解为一个新类 - 数据管理器。将数据管理器传递给每个视图控制器,以便他们可以使用它来下载所需的内容。
如果这是一个线程问题,那么启用核心数据线程异常可以帮助您找到原因。
请注意,在每个视图控制器中使用FRC都可以,但是您应该只有一个主线程上下文,您可以将它们全部设置为。