【问题标题】:RestKit Mapping for different web services in different view controllers不同视图控制器中不同 Web 服务的 RestKit 映射
【发布时间】:2016-02-06 12:07:17
【问题描述】:

我正在开发一个 iPad 应用程序。我有三个不同的视图控制器,其中我使用 RestKit 调用三个不同的 Web 服务并将它们映射到核心数据实体。我使用 NSFetchedResultsController 在所有视图控制器中显示数据。

当我第一次尝试加载数据时,它在所有视图控制器上都能正常工作。后来当我来到第一个视图控制器并尝试加载数据时,它失败了。我觉得我在搞砸什么。

这是我的代码。在 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];

viewStockRestKitManagedObjectContext = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
takeStockRestKitManagedObjectContext = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
takeStockItemsByLocationRestKitManagedObjectContext = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;

在第一个视图控制器中,我设置了映射和其他所需的东西,如下所示:

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:viewStockRequestPath];

    NSDictionary *argsDict = nil;
    BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];

    if (match) {
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"StoreItems"];
        return fetchRequest;
    }

    return nil;
}];

RKEntityMapping *storeItemsListMapping = [RKEntityMapping mappingForEntityForName:@"StoreItems" inManagedObjectStore: managedObjectStore];
storeItemsListMapping.identificationAttributes = @[@"itemId"];

[storeItemsListMapping addAttributeMappingsFromDictionary:
 @{
   @"itemId" : @"itemId",
   @"itemName" : @"itemName",
   @"itemCode" : @"itemCode",
   @"uomCode" : @"uomCode",
   @"locId" : @"locId",
   @"locName" : @"locName",
   @"subLocId" : @"subLocId",
   @"subLocName" : @"subLocName",
   @"storeItemId" : @"storeItemId"
   }
 ];

RKResponseDescriptor *storeItemsListResponseDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:storeItemsListMapping
                                             method:RKRequestMethodGET
                                        pathPattern:nil
                                            keyPath:nil
                                        statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

[objectManager addResponseDescriptor:storeItemsListResponseDescriptor];

然后我得到对象:

 [[RKObjectManager sharedManager]
 getObjectsAtPath:viewStockRequestPath
 parameters:nil
 success: ^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
     NSLog(@"requestDataItemsForStore - Mapping Success");
      NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"StoreItems"];

NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"locName" ascending:YES];
fetchRequest.sortDescriptors = @[descriptor];

NSError *error = nil;
[[appDelegate viewStockRestKitManagedObjectContext] executeFetchRequest:fetchRequest error:&error];
      NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
}
     [self.tableView reloadData];
 }
 failure: ^(RKObjectRequestOperation *operation, NSError *error) {
     RKLogError(@"Load failed with error: %@", error);
     NSLog(@"requestDataItemsForStore - Loading Failed");
 }
 ];

这里是 fetchedresultscontroller 代码:

- (NSFetchedResultsController *)fetchedResultsController {
if (viewStockFetchedResultsController != nil) {
    return viewStockFetchedResultsController;
}

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"StoreItems" inManagedObjectContext:[appDelegate viewStockRestKitManagedObjectContext]];
[fetchRequest setEntity:entity];
NSSortDescriptor *rackNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"locName" ascending:YES];
NSArray *sortDescriptors = @[rackNameDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
viewStockFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[appDelegate viewStockRestKitManagedObjectContext] sectionNameKeyPath:@"locName" cacheName:nil];
viewStockFetchedResultsController.delegate = self;
return viewStockFetchedResultsController;

}

在其他视图控制器中,我调用不同的 Web 服务并映射到不同的核心数据实体:

这是其他视图控制器中的代码:

 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:nil
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)
];
[objectManager addResponseDescriptor:rackStockTakeStatusListResponseDescriptor];
then getting the objects:
NSString *requestPath = [NSString stringWithFormat:@"/stocktake/stocktake/%@/usr/1/locwithstatus",[defaults objectForKey:@"loggedInUserSelectedStoreId"]];
[[RKObjectManager sharedManager]
getObjectsAtPath:requestPath
parameters:nil
success: ^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RackStockTakeStatus" inManagedObjectContext:[appDelegate takeStockRestKitManagedObjectContext]];
[request setEntity:entity];
NSError *error;
[[appDelegate takeStockRestKitManagedObjectContext] executeFetchRequest:request error:&error];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
[self.tableView reloadData];
NSLog(@"requestDataItemsForStore - Mapping Success");
}
failure: ^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(@"Load failed with error: %@", error);
NSLog(@"requestDataItemsForStore - Loading Failed");
}
];

FetchedResultsController 代码:

- (NSFetchedResultsController *)fetchedResultsController {
    
    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"RackStockTakeStatus" inManagedObjectContext:[appDelegate takeStockRestKitManagedObjectContext]];
    [fetchRequest setEntity:entity];
    NSSortDescriptor *rackNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"locName" ascending:YES];
    NSArray *sortDescriptors = @[rackNameDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
   fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[appDelegate takeStockRestKitManagedObjectContext] sectionNameKeyPath:nil cacheName:nil];
    fetchedResultsController.delegate = self;
return fetchedResultsController;
}

您能帮我找出问题所在吗?

【问题讨论】:

  • 失败怎么办?因为您要添加重复的映射?还是因为您要切换对象存储?集中你的设置,这样你就不会重复做 - 即不要把它放在视图控制器中。
  • @Wain,当我切换视图控制器时,它会以某种方式加载其他视图控制器所需的数据。我不确定为什么会发生这种情况。我不认为我有重复的映射,请您指出重复的映射吗?
  • 加载其他VC数据是什么意思?你没有展示任何其他风投。您是否在每个 VC 中添加所有相同的映射 a?提出所有相同的要求?没有谓词?
  • @Wain,感谢您的回复。我已经更新了帖子以将代码包含在其他 VC 中。您的指导会很有帮助。

标签: ios objective-c core-data restkit


【解决方案1】:

问题是您所有的响应描述符路径模式都是零。这意味着所有响应描述符都将应用于所有响应。 RestKit 将为匹配描述符创建它被告知的任何实体的实例,无论描述符中有多少个键被发现要映射。因此,您将获得大量创建的错误类型的部分填充实例。

要解决此问题,请将每个响应描述符的路径模式设置为与请求 URL 路径匹配。

【讨论】:

  • 这似乎解决了数据加载问题。现在我在其中一个vc中面临不同。应用程序因以下错误而崩溃:
  • 这里是崩溃日志:I restkit.core_data:RKInMemoryManagedObjectCache.m:94 通过属性 'stockTakeLocId' 缓存实体 'RackStockTakeStatus' 的实例 *** -[RKEntityByAttributeCache addObjects:completion:] 中的断言失败, StockTake/Pods/RestKit/Code/CoreData/RKEntityByAttributeCache.m:333 ** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无法将具有实体“RackStockTakeStatus”的对象添加到“RackStockTakeStatus”实体的缓存中跨度>
  • 请提出一个新问题,包括崩溃详细信息、完整的堆栈跟踪以及该实体的映射和请求代码
  • 当然。非常感谢您解决这个问题。
  • 没问题,欢迎来到 SO。记得勾选并投票帮助和解决问题的答案:-)实际上我看到你已经成为会员有一段时间了,只是不是一个大用户:-)
猜你喜欢
  • 1970-01-01
  • 2012-10-08
  • 1970-01-01
  • 1970-01-01
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多