I'm building an iOS app that uses web services extensively. I've built classes that handle the requests. However since there are a lot of web service request. I need to find out how to detect which web service to run, based on the action - registration, login, image upload, etc.
This is just a small snippet of a very large method I came up with:
- (BOOL) wsExecution:(int) wsID wsParameters: (NSDictionary*) parameters
{
switch (wsID)
{
case WEB_SERVICE_ID
{
ClassWS* ws = [[ClassWS alloc] initWithURL:WEB_SERVICE_ID Url:WEB_SERVICE_URL];
break;
}
case AAWEB_SERVICE_ID
{
ClassWS* ws = [[ClassWS alloc] initWithURL:AAWEB_SERVICE_ID Url:AAWEB_SERVICE_URL];
break;
}
The web service IDs are defined in a file called constants. I then map a URL to an ID in the method above. There are another 30 switch cases in this method. The Web Service IDs are just int
s that have no relevance to the actual web service. It was just a way to check which service, based on a switch statement.
It makes it hard to read and I think it can be done better. Is there a way to do with and remove the notion of a web service ID completely?
To be a little more clear on where I am going with this:
Here is another example of the switch case (I have counted 200 cases):
switch (wsID)
{
case RUN_ORDER_WS_ID:
{
NSDictionary* postData = [NSDictionary dictionaryWithObject:[parameters objectForKey:@"OrderResponse"] forKey:@"OrderResponse"];
NSMutableDictionary* newParams = [NSMutableDictionary dictionaryWithDictionary:parameters];
OrderWS* ws = [[OrderWS alloc] initWithURL:RUN_ORDER_WS_ID Url:RUN_ORDER_WS_ID_WS_URL];
self.placeClassifiedResponseWS = ws;
ws.delegate = self;
[newParams removeObjectForKey:@"OrderResponse"];
[ws fetch:newParams PostDataValuesAndKeys:postData];
[ws release];
break;
}
case GET_LIST_OF_USERS_ID:
{
NSDictionary* postData = [NSDictionary dictionaryWithObject:[parameters objectForKey:@"userList"] forKey:@"userList"];
NSMutableDictionary* newParams = [NSMutableDictionary dictionaryWithDictionary:parameters];
UsersWS* ws = [[UsersWS alloc] initWithURL:GET_LIST_OF_USERS_ID Url:GET_LIST_OF_USERS_URL];
self.userListWS = ws;
ws.delegate = self;
[newParams removeObjectForKey:@"userList"];
[ws fetch:newParams PostDataValuesAndKeys:postData];
[ws release];
break;
}
case GET_USER_REVIEW_FROM_ITEMS_WS_ID:
{
NSString* itemId = [parameters objectForKey:@"itemId"];
NSMutableDictionary* newParams = [NSMutableDictionary dictionaryWithDictionary:parameters];
NSString* newURL = [NSString stringWithFormat:GET_USER_REVIEW_FROM_ITEMS_WS_URL, itemId];
DataStoreWS = [[DataStoreWS alloc] initForComponents: [NSArray arrayWithObjects:REVIEW_COMPONENT, nil] WebserviceID: wsID Url:newURL];
self.reviewOfUserWS = ws;
ws.delegate = self;
[newParams removeObjectForKey:@"itemId"];
[ws fetch:newParams];
[ws release];
break;
}
1 Answer 1
Here's a quick and dirty example to illustrate the benefit of the dictionary setup:
- (NSDictionary *)webServiceIDsAndURLs{
NSDictionary *sillyExampleDictionary = @{ @1 : [NSURL URLWithString:@"http://www.noreagle.com"],
@2 : [NSURL URLWithString:@"http://www.stackOverflow.com"],
@3 : [NSURL URLWithString:@"http://www.etc.com"]};
return sillyExampleDictionary;
}
...
- (BOOL) webServicesExecution:(NSNumber *) webServiceID webServiceParameters: (NSDictionary*) parameters{
NSURL *URL = [[self webServiceIDsAndURLs] objectForKey:webServiceID];
ClassWebService *webService = [[ClassWebService alloc] initWithID:webServiceID URL:URL];
// see, no lengty switch, yay!
return YES; // Not sure what you are planning here...
}
-
\$\begingroup\$ Thanks for the quick example - much appreciate. The problem is that I won't be executing the same class / method on all web service IDs. Depending on the web service ID - I execute a few different web services - /search / image upload / buyer info - etc. Would NSDictionary allow for this sort of thing? \$\endgroup\$Robert J. Clegg– Robert J. Clegg2013年11月05日 06:10:17 +00:00Commented Nov 5, 2013 at 6:10
-
\$\begingroup\$ The more I think about this then more I don't see how to get passed a switch statement. I'm telling the code to do this: "If web service is (ID or URL, doesn't matter) then do this" now the last action is anything from running a method in another class to creating and dictionary. \$\endgroup\$Robert J. Clegg– Robert J. Clegg2013年11月05日 07:16:27 +00:00Commented Nov 5, 2013 at 7:16
-
\$\begingroup\$ Without detailed knowledge about your project its hard to be very concrete. It sounds like you will need SOME logic outside the dictionary stuff. It do sound however that you would be able to trim down the logic of the switch statement quite a lot if you limit this to actually messaging the methods: Find the URL from the dictionary first then lump together whatever ID's that makes sense to perform the different services... \$\endgroup\$T. Benjamin Larsen– T. Benjamin Larsen2013年11月05日 07:39:13 +00:00Commented Nov 5, 2013 at 7:39
-
\$\begingroup\$ I have updated my question with a more complete version of the switch statement. I really like the NSDictionary idea - but it seems I can't get passed the comparison that the switch does.. 200 odd times.. any thoughts? Appreciate the feedback. \$\endgroup\$Robert J. Clegg– Robert J. Clegg2013年11月05日 07:55:49 +00:00Commented Nov 5, 2013 at 7:55
-
\$\begingroup\$ Only knowing what you show me I'd say 1.Put the creation of the postData dictionary outside the switch statement, it is calling the same method after all. Pass the key into the method instead of defining it inside the method scope. Those two things alone will leave you with only the two different User/order instances and the properties. \$\endgroup\$T. Benjamin Larsen– T. Benjamin Larsen2013年11月05日 08:13:34 +00:00Commented Nov 5, 2013 at 8:13
initWithURL:(not a URL!) Url:(wait, here's the URL?)
\$\endgroup\$@[...]
for NSArray or@"..."
for NSString. \$\endgroup\$