问题
I have two EndPoints:
http://rest.domain.com/invite
http://rest.domain.com/template
Depending on what options the User selects, I need to able to PUT
, POST
, & Delete
on both EndPoints.
Mapping for all three methods is slightly different. Mapping for each EndPoint is also different.
What's the best way to setup mappings so they are loaded once and can be used multiple times for each EndPoint depending upon what option (PUT
, POST
, or Delete
) the User selects? I have to accomplish this on one storyboard Scene!
Currently, below is the code that I use when POST
ing to the /invite
EndPoint (it crashes after the first POST b/c I'm remapping):
- (void)sendInvite:(NSInteger)methodType
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.objectManager = [self getObjectManager];
self.objectManager.managedObjectStore = appDelegate.managedObjectStore;
RKEntityMapping *invitationMapping = [RKEntityMapping mappingForEntityForName:kInvite
inManagedObjectStore:self.objectManager.managedObjectStore];
RKEntityMapping *activityMapping = [RKEntityMapping mappingForEntityForName:kActivity
inManagedObjectStore:self.objectManager.managedObjectStore];
Invite *invitation;
switch (methodType) {
case POST:
{
invitationMapping = [RESTMappingProvider invitionPostMapping:invitationMapping];
activityMapping = [RESTMappingProvider activityPostMapping:activityMapping];
[invitationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:kActivitiesRelationship
toKeyPath:kActivitiesRelationship
withMapping:activityMapping]];
invitation = [self inviteForMethod:POST]; //This method just assigns values to the attributes
[self setupDescriptors:invitationMapping forKeyPath:kMeetupKeyPath descriptorClassIsTemplate:NO];
[self.objectManager.HTTPClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[self.objectManager.managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:NO];
[self.objectManager postObject:invitation path:kMeetupKeyPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
[self removeDuplicateObjects]; //After removing relationship Dups, I save to persistent store
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
}
break;
case PUTACCEPT:
case PUTDECLINE:
case PUTEDIT:
{
invitationMapping = [RESTMappingProvider invitionPutMapping:invitationMapping];
activityMapping = [RESTMappingProvider activityPutMapping:activityMapping];
[invitationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:kActivitiesRelationship
toKeyPath:kActivitiesRelationship
withMapping:activityMapping]];
invitation = [self inviteForMethod:methodType]; //This method just assigns values to the attributes
[self setupDescriptors:invitationMapping forKeyPath:kMeetupKeyPath descriptorClassIsTemplate:NO];
[self.objectManager.HTTPClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[self.objectManager putObject:invitation path:kMeetupKeyPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"Failure in PUT");
}];
}
break;
}
}
I do something similar for the Templates EndPoint
- (void)saveAsTemplate
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.objectManager = [self getObjectManager];
self.objectManager.managedObjectStore = appDelegate.managedObjectStore;
RKEntityMapping *invitationMapping = [RKEntityMapping mappingForEntityForName:kInviteTemplates
inManagedObjectStore:self.objectManager.managedObjectStore];
invitationMapping = [RESTMappingProvider invitionTemplateMapping:invitationMapping];
RKEntityMapping *activityMapping = [RKEntityMapping mappingForEntityForName:kActivityTemplates
inManagedObjectStore:self.objectManager.managedObjectStore];
activityMapping = [RESTMappingProvider activityTemplateMapping:activityMapping];
[invitationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:kTemplateActivitiesRelationship
toKeyPath:kTemplateActivitiesRelationship
withMapping:activityMapping]];
STInvitesTemplate *invitation = [self templateForInvite];//this method assigns values to the attributes
[self setupDescriptors:invitationMapping forKeyPath:kTemplatesKeyPath descriptorClassIsTemplate:YES];
[self.objectManager.HTTPClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[self.objectManager postObject:invitation path:kTemplatesKeyPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
}
Request & Response Descriptor:
- (void)setupDescriptors:(RKEntityMapping *)invitationMapping forKeyPath:(NSString *)keyPath descriptorClassIsTemplate:(BOOL)isTemplate
{
RKRequestDescriptor *requestDescriptor;
if (isTemplate)
{
requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[invitationMapping inverseMapping] objectClass:[Template class] rootKeyPath:nil method:RKRequestMethodAny];
}
else
{
requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[invitationMapping inverseMapping] objectClass:[Invite class] rootKeyPath:nil method:RKRequestMethodAny];
}
NSIndexSet *statusCodeSet = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:invitationMapping
method:RKRequestMethodGET
pathPattern:keyPath
keyPath:nil
statusCodes:statusCodeSet];
self.objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[self.objectManager addRequestDescriptor:requestDescriptor];
[self.objectManager addResponseDescriptor:responseDescriptor];
}
I know the approach above is incorrect as Xcode crashes after I POST or PUT. I haven't implemented Delete yet b/c I'm not sure how to set this up correctly.
Do I load the mappings ONCE in viewDidLoad
? Do I create PUT, POST, DELETE
x 2 EndPoints
= 6 RKEntityMappings
?
Need some guidance on best practice. Code sample or some step-by-step instructions would be great!
回答1:
You need to create an many different mappings as you have different structure responses to process. If the responses for one entity type are all subsets of some common superset then you can use just one (for mapping responses and another for requests). You don't say anything about the expected JSON so I can't tell.
In your code I see 2 request descriptors and 1 response descriptor. The requests match against any method so will always be used. The response descriptor matches only GET responses so won't work for anything. You should likely have one response descriptor per end point per method (as you say they need different mappings to be applied to each).
viewDidLoad
isn't necessarily the correct place to configure this. It looks like you have a single object manager and this configuration code should run when it is created (not when it is used, brcause the view can be loaded multiple times and the configuration would be duplicated).
来源:https://stackoverflow.com/questions/23718498/restkit-two-endpoints-post-put-delete