Restkit 0.2 返回 RKMappingSourceObject 类型对象的一对多类型关系

Posted

技术标签:

【中文标题】Restkit 0.2 返回 RKMappingSourceObject 类型对象的一对多类型关系【英文标题】:Restkit 0.2 returning RKMappingSourceObject type Objects for one-to-many type relationship 【发布时间】:2014-02-10 09:48:49 【问题描述】:

我正在尝试在我的应用程序中映射 JSON 数组。我面临的问题是,我得到的不是 NSString 类型的对象,而是 RKMappingSourceObject 类型的对象。

响应格式为


         message =     
            Appetite =         
                    Breakfast = 4;
                    Dinner = 4;
                    Lunch = 4;
                ;
        PainSymptom =         
       Aching = 1;
                AtRest = 0;
                Awakes = 0;
                Burning = 0;
                Cramping = 0;
                    Location =             (
                        Head,
                        "Right Upper Leg",
                        "Left Upper Leg",
                        "Left Ankle/Foot",
                        "Right Ankle/Foot",
                        "Mid Back",
                        "Upper Back",
                        Tailbone
                    );
                ;
        

我的核心数据类是:

DTAttribute.h

@interface DTAttribute : NSManagedObject

@property (nonatomic, strong) NSString * attribute;
@property (nonatomic, strong) DTPainSymptom *painSymptom;

@end

DTAttribute.m

@implementation DTAttribute

@dynamic attribute;
@dynamic painSymptom;

@end

DTPainSymptom.h

@interface DTPainSymptom : NSManagedObject

@property (nonatomic, retain) NSNumber * aching;
@property (nonatomic, retain) NSNumber * atRest;
@property (nonatomic, retain) NSNumber * awakes;
@property (nonatomic, retain) NSNumber * burning;
@property (nonatomic, retain) NSNumber * cramping;
@property (nonatomic, retain) DTMyDay *myDay;
@property (nonatomic, retain) NSSet *painLocations;
@end

@interface DTPainSymptom (CoreDataGeneratedAccessors)

- (void)addPainLocationsObject:(DTAttribute *)value;
- (void)removePainLocationsObject:(DTAttribute *)value;
- (void)addPainLocations:(NSSet *)values;
- (void)removePainLocations:(NSSet *)values;

@end

DTPainSymptom.m

@implementation DTPainSymptom

@dynamic aching;
@dynamic atRest;
@dynamic awakes;
@dynamic burning;
@dynamic cramping;
@dynamic myDay;
@dynamic painLocations;

@end

DTMyDay.h

@interface DTMyDay : NSManagedObject

@property (nonatomic, retain) DTPainSymptom *painSymptom;

@end

DTMyDay.m

@implementation DTMyDay

@dynamic painSymptom;

@end

映射:

@implementation DTMyDay(映射)

+ (id) mapping 
  RKEntityMapping* myDayMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([DTMyDay class]) inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];

  RKEntityMapping* attributeMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([DTAttribute class]) inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];
  [attributeMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"attribute"]];

  //Pain Symptom
  RKEntityMapping* painSymptomMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([DTPainSymptom class]) inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];
  [painSymptomMapping addAttributeMappingsFromDictionary:@
                                                           @"Awakes": @"awakes",
                                                           @"AtRest": @"atRest",
                                                           @"Burning": @"burning",
                                                           @"Cramping": @"cramping",
                                                           @"Aching": @"aching",
                                                           ];
  [painSymptomMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"Location"
                                                                                     toKeyPath:@"painLocations"
                                                                                   withMapping:attributeMapping]];


  [myDayMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"message.PainSymptom"
                                                                               toKeyPath:@"painSymptom"
                                                                             withMapping:painSymptomMapping]];

  NSDateFormatter* dateFormatter = [NSDateFormatter new];
  [dateFormatter setDateFormat:@"yyyy-MM-dd"];
  myDayMapping.dateFormatters = [NSArray arrayWithObject: dateFormatter];
  return myDayMapping;



+ (id)responseDescriptor:(NSString *)pathPattern 
  RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[self mapping] pathPattern:pathPattern keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
  return responseDescriptor;


@end

这里的问题是与message.PainSymptom.Location 对应的值数组未正确映射。我在DTMyDay 类中得到一个与painLocations 对应的DTAttribute 类型对象数组。但是,当我尝试访问 painLocations 数组中每个 DTAttribute 类的属性属性时,我得到的是 RkMappingSourceObject 类型的对象,而不是 NSString 类型的对象。

我很抱歉这堵巨大的代码墙,但现在我真的不知道该怎么办。

这给我带来了一个问题,因为我将 dtAttribute.attribute 发送到一个方法,它返回我 NSNotFound 因为传递的对象是 RKMappingSourceObject 类型:

#define BODY_PARTS_NAMES @"Head", @"Right Shoulder", @"Neck", @"Left Shoulder", @"Right Chest", @"Left Chest", @"Right Arm", nil

- (BodyPart)bodyPartStringToEnum:(NSString *)strVal

    NSArray *bodyPartsArray = [[NSArray alloc] initWithObjects:BODY_PARTS_NAMES];
    NSUInteger index = [bodyPartsArray indexOfObject:strVal];

    return index;

【问题讨论】:

RKMappingSourceObject代理类给你带来了什么问题?它只是将所有方法调用转发给真正的对象。您是否尝试在某处使用字符串描述(与您期望的相比,这看起来很奇怪)? 我有一个函数,它接受一个 NSString 参数并返回一些值。当我向它发送 dtAttribute.attribute 时,它​​返回给我 NSNotFound 因为传递的对象是 RKMappingSourceObject 类型。 您能否将该方法的代码添加到您的问题中,我们会考虑修复它吗? #define BODY_PARTS_NAMES @"头",@"右肩",@"颈",@"左肩",@"右胸",@"左胸",@"右臂" , nil + (BodyPart) bodyPartStringToEnum:(NSString*)strVal NSArray *bodyPartsArray = [[NSArray alloc] initWithObjects:BODY_PARTS_NAMES]; NSUInteger index = [bodyPartsArray indexOfObject:strVal];回报指数;但是,如果 [dtAttribute.attribute mutableCopy] 则一切正常。 【参考方案1】:

RKMappingSourceObject 是 RestKit 内部使用的代理对象,用于处理映射过程中的自省问题和元数据。因为它是一个代理并转发所有方法调用,所以它只是在映射结束时返回。通常这不会导致问题。

我没想到它会根据您的代码引起问题,但显然比较方法中的某些内容不起作用。 RKMappingSourceObject 应该同时转发 class 请求和“正常”方法调用...

RKMappingSourceObject 有一个object 方法,问题是如何知道你应该调用它(因为该类应该作为NSString 的某个子类返回)。我会看一个讨厌的东西,比如:

- (BodyPart)bodyPartStringToEnum:(NSString *)strVal

    if ([strVal respondsToSelector:@selector(object)]) 
        strVal = [strVal object];
    

    NSArray *bodyPartsArray = [[NSArray alloc] initWithObjects:BODY_PARTS_NAMES];
    NSUInteger index = [bodyPartsArray indexOfObject:strVal];

    return index;

我不喜欢它,但希望它能够工作并与将来对代理对象的潜在更改(删除)兼容。或者,调试以确定比较失败的原因并查看更改代理实现。

【讨论】:

我想到了你的解决方法,现在我只是这样做。但是我在代码的其他地方遇到了问题,我在值属性上使用 NSPredicate 过滤了 painSymptom.painLocations(NSSet of DTAttribute) 集。它无法过滤该集合。 因此您可以将该代码移动到自定义访问器方法实现中(因此它始终用于从代理访问object)。我很想知道为什么代理不起作用,调试可能是最好的方法。可能有另一种使用copy 从代理创建新字符串的替代方法(可能在托管对象子类中)。【参考方案2】:

RKMappingSourceObject 转换为NSString 的另一种方式:

NSString *realString = [NSString stringWithString:stringProxy];

其中stringProxyRKMappingSourceObject 的一个实例。

【讨论】:

以上是关于Restkit 0.2 返回 RKMappingSourceObject 类型对象的一对多类型关系的主要内容,如果未能解决你的问题,请参考以下文章

Restkit 0.2 返回 RKMappingSourceObject 类型对象的一对多类型关系

Restkit 映射 0.2

RestKit 0.2x 同时 RKManagedObjectRequestOperation

如何在 RESTkit 0.2 中设置缓存策略

使用 RestKit 0.2 从 CoreData 获取本地数据

RestKit 0.2:扁平化 JSON 中的层次结构