primaryKeyAttribute不工作Restkit / Core Data
我刚刚安装了框架restkit 0.9.3,并按照讨论板的例子。 那么,一切工作都很好,但是当我尝试使用核心数据时,即使在声明他的primaryKeyAttribute(userID)之后,我的用户NSManagedObject类也是重复的。 例如,当我发送一个login请求到我的networking服务器,我返回{"user":{"id":1, "username":"teste", ...}}
..但它似乎创build一个每次新行都会调用objectLoader:didLoadObjects。
用户表:
示例代码:
〜AppDelegate.m didFinishLaunching
RKManagedObjectMapping* userMapping = [RKManagedObjectMapping mappingForClass:[User class]]; userMapping.primaryKeyAttribute = @"userID"; userMapping.setDefaultValueForMissingAttributes = YES; // clear out any missing attributes (token on logout) [userMapping mapKeyPathsToAttributes: @"id", @"userID", @"email", @"email", @"username", @"username", @"password", @"password", nil]; [objectManager.mappingProvider registerMapping:userMapping withRootKeyPath:@"user"];
〜User.m loginWithDelegate
- (void)loginWithDelegate:(NSObject<UserAuthenticationDelegate>*)delegate { _delegate = delegate; [[RKObjectManager sharedManager] postObject:self delegate:self block:^(RKObjectLoader* loader) { loader.resourcePath = @"/login"; loader.serializationMapping = [RKObjectMapping serializationMappingWithBlock:^(RKObjectMapping* mapping) { [mapping mapAttributes:@"username", @"password", nil]; }]; }]; }
〜User.m didLoadObjects(RKObjectLoaderDelegate)
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray *)objects { if ([objectLoader wasSentToResourcePath:@"/login"]) { [self loginWasSuccessful]; } NSLog(@"number of user rows: %i", [User findAll].count); }
我究竟做错了什么?
你正确地实现RKManagedObjectCache? 为了debugging,我只是简单地返回零,忘记了这一点。 过了一会儿,我发现我也有重复。
caching通过获取本地对象并与服务器返回的对象进行比较来工作。 任何不在服务器响应中的本地对象都将被删除。 在较早的版本中,它使用了一个获取请求,但在较新的版本中,您必须手动执行请求并返回实际的对象。
如果你返回零,它认为这个对象不在你的caching中,并会添加一个副本。 尝试实施这个方法:
+ (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute value:(id)primaryKeyValue inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
例如:
+ (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute value:(id)primaryKeyValue inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext { NSFetchRequest* request = [[NSFetchRequest alloc] init]; [request setEntity: entity]; [request setFetchLimit: 1]; [request setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", primaryKeyAttribute, primaryKeyValue]]; NSArray *results = [NSManagedObject executeFetchRequest:request inContext: managedObjectContext]; if ([results count] == 0) { return nil; } return [results objectAtIndex:0]; }
我发现与targetObject(RKObjectLoader)有关的问题
/** * The target object to map results back onto. If nil, a new object instance * for the appropriate mapping will be created. If not nil, the results will * be used to update the targetObject's attributes and relationships. */
所以当我把它设置为nil
postObject调用findOrCreateInstanceOfEntity:withPrimaryKeyAttribute:andValue
- (void)loginWithDelegate:(NSObject<UserAuthenticationDelegate>*)delegate { _delegate = delegate; [[RKObjectManager sharedManager] postObject:self delegate:self block:^(RKObjectLoader* loader) { loader.resourcePath = @"/login"; loader.targetObject = nil; loader.serializationMapping = [RKObjectMapping serializationMappingWithBlock:^(RKObjectMapping* mapping) { [mapping mapAttributes:@"username", @"password", nil]; }]; }]; }
从最新的RESTKit版本(0.23.2)开始,您可以像这样定义主键:
[_mapping addAttributeMappingsFromDictionary:@{ @"id" : @"objectId", @"name" : @"name" }]; [_mapping setIdentificationAttributes:@[ @"objectId" ]];
而objectId是核心数据对象的主键。