RestKit关系映射

时间:2013-09-18 15:11:19

标签: ios objective-c restkit restkit-0.20

我在使用RestKit映射关系时遇到问题(0.20.3)。我看过其他帖子但还没有找到解决方案。我想我很接近但仍然缺少一些东西。

问题

实体属性正好映射到Core Data;但是,如果实体有关系,则不会映射。我有一个解决方法,我需要摆脱它,因为它现在已达到极限。

对于变通方法,在成功映射之后,我已将托管对象ID传递给前台线程以水合有效的托管对象。然后我遍历对象并建立关系,然后“重新”到核心数据。

解决方法的问题是映射关系是identificationAttributes参数的唯一键的一部分。由于映射在后台运行不正常,因此未正确识别现有记录,因此在将来的API调用中会出现重复条目​​。

背景

可以下载示例源XML here

XML的基本结构如下:

<locations>
  <location lat="38.8561" lon="-94.6654" timezone="UTC" city="Overland Park" region="KS" country="US" zipcode="66223" offset="0" local_offset_hours="-5">
    <sfc_ob>
      <attribute1></attribute1>
    </sfc_ob>
    <daily_summaries>
      <daily_summary>
        <attribute2> </attribute2>
      <daily_summary>
    </daily_summaries>
    <hourly_summaries>
      <hourly_summary>
        <attribute3></attribute3>
      </hourly_summary>
    </hourly_summaries>
  </location>
</locations>

我的核心数据实体如下:

enter image description here enter image description here enter image description here

RESTKIT相关代码

- (GLWeatherManager *)init {
self = [super init];

// setup logging
RKLogConfigureByName("RestKit/Network*", RKLogLevelTrace);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);

self.httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:@"http://weather.wdtinc.com"]];
[self.httpClient setDefaultHeader:@"Accept" value:RKMIMETypeXML];
[RKMIMETypeSerialization registerClass:[RKXMLReaderSerialization class] forMIMEType:@"application/xml"];
self.restKitManager = [[RKObjectManager alloc] initWithHTTPClient:self.httpClient];
self.restKitManager.managedObjectStore = [[RKManagedObjectStore alloc] initWithPersistentStoreCoordinator:[NSPersistentStoreCoordinator MR_defaultStoreCoordinator]];
[self.restKitManager.managedObjectStore createManagedObjectContexts];

// Locations
RKEntityMapping *locationMapping = [self buildMapForLocations];
RKEntityMapping *currentConditionsMapping = [self buildMapForCurrentConditions];
RKEntityMapping *dailySummariesMapping = [self buildMapForDailySummaries];
RKEntityMapping *hourlyForecastsMapping = [self buildMapForHourlyForecasts];

[locationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations.location.daily_summaries" toKeyPath:@"dailySummaries" withMapping:dailySummariesMapping]];
[locationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations.location.hourly_summaries" toKeyPath:@"hourlyForecasts" withMapping:hourlyForecastsMapping]];
[locationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations.location.sfc_ob" toKeyPath:@"currentConditions" withMapping:currentConditionsMapping]];

[currentConditionsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations.location" toKeyPath:@"location" withMapping:locationMapping]];
[dailySummariesMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations.location" toKeyPath:@"location" withMapping:locationMapping]];
[hourlyForecastsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations.location" toKeyPath:@"location" withMapping:locationMapping]];

RKResponseDescriptor *descriptor = [RKResponseDescriptor  responseDescriptorWithMapping:locationMapping pathPattern:@"/feeds/demofeeds20131031/mega.php" keyPath:@"locations.location" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];                        

// add mapping description to objectmanager
[self.restKitManager addResponseDescriptor:descriptor];

RKResponseDescriptor *descriptor2 = [RKResponseDescriptor responseDescriptorWithMapping:currentConditionsMapping pathPattern:@"/feeds/demofeeds20131031/mega.php" keyPath:@"locations.location.sfc_ob"                                                              statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

[self.restKitManager addResponseDescriptor:descriptor2];

RKResponseDescriptor *descriptor3 = [RKResponseDescriptor responseDescriptorWithMapping:dailySummariesMapping                                    pathPattern:@"/feeds/demofeeds20131031/mega.php"                                                 keyPath:@"locations.location.daily_summaries.daily_summary"                                          statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

    [self.restKitManager addResponseDescriptor:descriptor3];

    RKResponseDescriptor *descriptor4 = [RKResponseDescriptor responseDescriptorWithMapping:hourlyForecastsMapping                                               pathPattern:@"/feeds/demofeeds20131031/mega.php"                                                                keyPath:@"locations.location.hourly_summaries.hourly_summary"
                                                                                statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

    [self.restKitManager addResponseDescriptor:descriptor4];

// start the location manager to get the current location
self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager setDelegate:self];
[self.locationManager startUpdatingLocation];

self.locations = [NSMutableArray arrayWithArray:[Locations findAll]];

[self getMegaFeed];

return self;

}


- (RKEntityMapping *)buildMapForLocations {
RKEntityMapping *locationMapping = [RKEntityMapping mappingForEntityForName:@"Locations" inManagedObjectStore:self.restKitManager.managedObjectStore];
[locationMapping addAttributeMappingsFromDictionary:@{
 @"lat" : @"latitude",
 @"lon" : @"longitude",
 @"city" : @"city",
 @"region" : @"region",
 @"country" : @"country",
 @"zipcode" : @"zipcode",
 }];
locationMapping.identificationAttributes = [NSArray arrayWithObject:@"zipcode"];

return locationMapping;
}

    - (RKEntityMapping *)buildMapForCurrentConditions {
    // Current Conditions
    RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"CurrentConditions" inManagedObjectStore:self.restKitManager.managedObjectStore];
    [mapping addAttributeMappingsFromDictionary:@{
     //@"stn" : @"stn",
     //@"location" : @"location",
     //@"stn_lat" : @"stnLatitude",
     //@"stn_lon" : @"stnLongitude",
     @"ob_time.text" : @"observationTime",
     @"day_of_week.text" : @"dayOfWeek",
     @"temp_C.text" : @"temperatureMetric",
     @"temp_F.text" : @"temperatureImperial",
     @"dewp_C.text" : @"dewPointMetric",
     @"dewp_F.text" : @"dewPointImperial",
     @"rh_pct.text" : @"relativeHumidity",
     @"wnd_dir.text" : @"windDirection",
     @"wnd_spd_mph.text" : @"windSpeedImperial",
     @"wnd_spd_kph.text" : @"windSpeedMetric",
     @"press_in.text" : @"pressureImperial",
     @"press_mb.text" : @"pressureMetric",
     @"wx.text" : @"conditionSummary",
     @"wx_code.text" : @"conditionCode",
     @"cld_cover.text" : @"cloudCover",
     @"visibility_ft.text" : @"visibilityImperial",
     @"visibility_m.text" : @"visibilityMetric",
     @"apparent_temp_F.text" : @"feelsLikeTemperatureImperial",
     @"apparent_temp_C.text" : @"feelsLikeTemperatureMetric",
     @"moon_phase.text" : @"moonPhase",
     @"sunrise_utc.text" : @"sunrise",
     @"sunset_utc.text" : @"sunset"
     }];

    [mapping setIdentificationAttributes:[NSArray arrayWithObjects:@"observationTime", nil]];

    return mapping;

}

- (RKEntityMapping *)buildMapForDailySummaries {
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"DailySummaries" inManagedObjectStore:self.restKitManager.managedObjectStore];
[mapping addAttributeMappingsFromDictionary:@{
 @"summary_date.text" : @"date",
 @"day_of_week.text" : @"dayOfWeek",
 @"max_temp_F.text" : @"tempMaxImperial",
 @"max_temp_C.text" : @"tempMaxMetric",
 @"min_temp_F.text" : @"tempMinImperial",
 @"min_temp_C.text" : @"tempMinMetric",
 @"wnd_spd_mph.text" : @"windSpeedImperial",
 @"wnd_spd_kph.text" : @"windSpeedMetric",
 @"min_wnd_spd_mph.text" : @"windSpeedMinImperial",
 @"min_wnd_spd_kph.text" : @"windSpeedMinMetric",
 @"max_wnd_spd_mph.text" : @"windSpeedMaxImperial",
 @"max_wnd_spd_kph.text" : @"windSpeedMaxMetric",
 @"wnd_gust_mph.text" : @"windGustImperial",
 @"wnd_gust_kph.text" : @"windGustMetric",
 @"wnd_dir.text" : @"windDirection",
 @"pop.text" : @"probabilityOfPrecipitation",
 @"wx.text" : @"conditionSummary",
 @"wx_code.text" : @"conditionCode",
 @"text_description.text" : @"textDescription",
 @"sunrise_utc.text" : @"sunrise",
 @"sunset_utc.text" : @"sunset",
 @"locations.location.zipcode.text" : @"locationZipcode"
 }];
mapping.identificationAttributes = [NSArray arrayWithObjects:@"date", @"locationZipcode", nil];
[mapping addConnectionForRelationship:@"location" connectedBy:@{@"locationZipcode": @"zipcode"}];
return mapping;

}

- (RKEntityMapping *)buildMapForHourlyForecasts {
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"HourlyForecasts" inManagedObjectStore:self.restKitManager.managedObjectStore];
[mapping addAttributeMappingsFromDictionary:@{
 @"day_of_week_utc.text" : @"dayOfWeek",
 @"time_utc.text" : @"forecastTime",
 @"temp_C.text" : @"temperatureMetric",
 @"temp_F.text" : @"temperatureImperial",
 @"dewp_C.text" : @"dewPointMetric",
 @"dewp_F.text" : @"dewPointImperial",
 @"app_temp_C.text" : @"feelsLikeTemperatureMetric",
 @"app_temp_F.text" : @"feelsLikeTemperatureImperial",
 @"rh_pct.text" : @"relativeHumidity",
 @"wx.text" : @"conditionSummary",
 @"wx_code.text" : @"conditionCode",
 @"day_night.text" : @"dayNight",
 @"pop.text" : @"probabilityOfPrecipitation",
 @"sky_cov_pct.text" : @"skyCoverPercent",
 @"wnd_dir.text" : @"windDirection",
 @"wnd_dir_degs.text" : @"windDirectionDegrees",
 @"wnd_spd_mph.text" : @"windSpeedImperial",
 @"wnd_spd_kph.text" : @"windSpeedMetric",
 @"locations.location.zipcode.text" : @"locationZipcode"
 }];

mapping.identificationAttributes = [NSArray arrayWithObjects:@"forecastTime", @"locationZipcode", nil];
[mapping addConnectionForRelationship:@"location" connectedBy:@{@"locationZipcode": @"zipcode"}];
return mapping;

}

- (void)getMegaFeed {
for (Locations *location in self.locations) {
    NSString *path = [NSString stringWithFormat:@"/feeds/demofeeds20131031/mega.php?ZIP=%@&UNITS=all",location.zipcode];
    // fetch data
    [self.restKitManager getObjectsAtPath:path
                               parameters:nil
                                  success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {

                                      NSArray *mappedObjects = [mappingResult array];
                                      NSMutableArray *validObjectIDs = [[NSMutableArray alloc] initWithCapacity:[mappedObjects count]];

                                      for (NSManagedObject *object in mappedObjects) {
                                          NSManagedObjectID *moID = [object objectID];
                                          [validObjectIDs addObject:moID];
                                      }
                                      [self notifyObservers:@selector(megaFeedDidFinish:location:) withObject:validObjectIDs withObject:location];


                                  }
                                  failure:^(RKObjectRequestOperation *operation, NSError *error) {
                                      [REUtility showDefaultAlertWithError:error];
                                      [RELog error:@"%s Hit error:%@", __func__, error];
                                  }];

}

}

更新

@WAIN

我尝试按照您的建议更改代码。当前条件对象似乎正确地接收了一个位置,但它是一对一的关系。其他是一对多的仍然没有正确映射。测试的代码更改如下:

 [locationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"daily_summaries" toKeyPath:@"dailySummaries" withMapping:dailySummariesMapping]];
[locationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"hourly_summaries" toKeyPath:@"hourlyForecasts" withMapping:hourlyForecastsMapping]];
[locationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"sfc_ob" toKeyPath:@"currentConditions" withMapping:currentConditionsMapping]];

[currentConditionsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"location" toKeyPath:@"location" withMapping:locationMapping]];
[dailySummariesMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"location" toKeyPath:@"location" withMapping:locationMapping]];
[hourlyForecastsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"location" toKeyPath:@"location" withMapping:locationMapping]];

1 个答案:

答案 0 :(得分:1)

所有关系映射的路径都是错误的。它们目前包含@"locations.location.daily_summaries"之类的内容,但应该是@"daily_summaries"。您应该在跟踪日志中看到在映射过程中未找到关键路径的关系。