Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Mockup & CodeGen, iPhone & iPad
($9.99)

Make your own iPhone apps
and run them live!
(free)

Manu
($0.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum

View Single Post
Old 04-23-2009, 12:49 AM   #57 (permalink)
ashwanik04
New Member
 
Join Date: Apr 2009
Posts: 16
Default Order of calling web service

Quote:
Originally Posted by Trilitech View Post
Like many others I wrote an app that was heavily dependent on asp.net SOAP web services that worked great in the simulator and then got hit with the surprise that the CoreServices library that contained all the web service functionality wasn't actually available on the iPhone. I'm still holding out hope this functionality will be added eventually.

All my code was dependant on receiving back the NSDictionary and NSArray object tree, and I didn't want to rewrite it all, so I created a wrapper to emulate the missing SOAP functionality by passing the request over REST. This allowed me to just swap out the method I was using for the webservice calls and keep the rest of the code the same. I thought I'd share it for anyone else in the same boat.

Fortunately asp.net already supports REST style requests (I didn't realize this before today), so no changes were needed on the web server side.

To demonstrate here the call to a simple method called "SayHello". You pass in name and it returns a single item called "string" that contains "Hello [yourname]". The code will work with more complex objects with child properties as well, and return them as NSDictionary and NSArray objects, but for simplicity I'm using "SayHello".

Code:
NSArray *keys = [NSArray arrayWithObjects:@"userName", nil];
NSArray *objects = [NSArray arrayWithObjects:@"jeremy", nil];
NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSDictionary *wsResponse=[WebServices callRestService:@"SayHello" :params];

NSString *responseString=[wsResponse objectForKey:@"string"];
callRestService is a helper method I created in a class called Webservices. This code was exactly the same before except the helper method was called callSoapService.

WebServices.m contains two methods. getRestUrl just appends all the method parameters into a url to make the REST request. callRestService uses the build-in NSXMLParser class to retrieve the xml and sends it to a custom class called XmlParser to handle the callbacks and create the NSDictionary result,

WebServices.m
Code:
+(id)callRestService: (NSString *) methodName : (NSDictionary *) params
{
	NSURL *url=[WebServices getRestUrl: methodName : params];
	XmlParser *xmlParser = [[XmlParser alloc] init];
	
	NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
	[parser setDelegate:xmlParser];
	[parser setShouldProcessNamespaces:NO];
	[parser setShouldReportNamespacePrefixes:NO];
	[parser setShouldResolveExternalEntities:NO];
	[parser parse];
	[parser release];
	return xmlParser.result;
}

+(NSURL *)getRestUrl: (NSString *) methodName : (NSDictionary *) params
{
	NSString *url=@"http://services.mywebsite.com/mywebservice.asmx/";
	url=[url stringByAppendingString:methodName];
	
	BOOL firstKey=TRUE;
	for (NSString *key in params)
	{
		NSString *value=[params objectForKey:key];
		if (firstKey) url=[url stringByAppendingString:@"?"]; else url=[url stringByAppendingString:@"&"];
		url=[url stringByAppendingString:key];
		url=[url stringByAppendingString:@"="];
		url=[url stringByAppendingString:value];
		firstKey=FALSE;
	}
	return [NSURL URLWithString:url];
}

The final step is to create the XmlParser handler. This class keeps track of each open and close tag to build an object tree containing NSMutableArray NSMutableDictionary and NSString objects.

XmlParser.h
Code:
#import <Foundation/Foundation.h>


@interface XmlParser : NSObject {
	NSMutableDictionary *result;
	NSString *currentElementName;
	NSString *currentElementValue;
	NSMutableArray *parentArray;
}

@property (nonatomic, retain) NSMutableDictionary *result;
@property (nonatomic, retain) NSString *currentElementName;
@property (nonatomic, retain) NSString *currentElementValue;
@property (nonatomic, retain) NSMutableArray *parentArray;


- (void)parserDidStartDocument:(NSXMLParser *)parser;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;

@end

XmlParser.m
Code:
#import "XmlParser.h"


@implementation XmlParser
@synthesize result;
@synthesize currentElementName;
@synthesize currentElementValue;
@synthesize parentArray;


- (void)parserDidStartDocument:(NSXMLParser *)parser
{
	result=[[NSMutableDictionary alloc] init];
	parentArray=[[NSMutableArray alloc] init];
	[parentArray addObject:result];
	currentElementName=@"";
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
	if (qName) {
		elementName = qName;
	}
	currentElementValue=@"";
	if (currentElementName!=@"")
	{
		id newParent=NULL;
		if ([currentElementName isLike:@"*Array*"])
		{
			newParent=[[NSMutableArray alloc] init];
		} else {
			newParent=[[NSMutableDictionary alloc] init];
		}
		[parentArray addObject:newParent];
	}
	currentElementName=elementName;
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{     
	if (qName) {
		elementName = qName;
	}
	
	if (currentElementName==@"")
	{
		//We're adding a container with children.  Add it to the parent and remove this item fromt he parentArray
		int currentIndex=[parentArray count]-1;
		int parentIndex=currentIndex - 1;
		id currentChild=[parentArray objectAtIndex:currentIndex];
		id currentParent=[parentArray objectAtIndex:parentIndex];
		
		if ([currentParent isKindOfClass:[NSMutableArray class]])
		{
			[currentParent addObject:currentChild];
		} else {
			[currentParent setObject:currentChild forKey:elementName];
		}
		
		[parentArray removeObjectAtIndex:currentIndex];
	} else {
		//We're adding a simple type element
		int currentIndex=[parentArray count]-1;
		id currentParent=[parentArray objectAtIndex:currentIndex];
		if ([currentParent isKindOfClass:[NSMutableArray class]])
		{
			[currentParent addObject:currentElementValue];
		} else {
			[currentParent setObject:currentElementValue forKey:currentElementName];
		}
	}
	currentElementName=@"";
}


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
	currentElementValue=string;
}

@end
That's it. I'm sure it's not the cleanest code (This is my very first XCode app) and there may be a better way of doing this, but it saved me from having to rewrite all my code that was retrieving data from SOAP services. I've seen tons of other people with the same problem and no solutions so far. I hope this helps.
Hello:
I followed your approach. I am able to call the web service. But I am having an issue please help me in that.

I have an application which when starts first time on the device, then it calls a web service which gives some data and stores it in a xml file for future use. After this call, I am reading the xml file and showing the data in table view. But for the first time, the file is not created before the view load, so no data is displayed. But if I run the application next time, as the file has been created , the table view displays the data.
My problem is that even in the first time also the data should be created before the view load and the data is displayed in the table view.

Please help me in this issue.
ashwanik04 is offline   Reply With Quote
 

» Advertisements
» Online Users: 350
16 members and 334 guests
acegames, ADY, BdR, catedawn, ChenXin, ckgni, Darmanikles, dfvdan, gagack, iph_s, MarkC, RoryHarvey, technovelty, thebinaryfamily, zacharyse, zbynda
Most users ever online was 1,187, 10-11-2011 at 08:09 AM.
» Stats
Members: 158,874
Threads: 89,225
Posts: 380,698
Top Poster: BrianSlick (7,129)
Welcome to our newest member, catedawn
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 07:01 AM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.