When I use the following code I was told there is a leak:
- (void)dealloc
{
[connection release], connection = nil;
[responseData release],responseData = nil;
[cityCode release], cityCode = nil;
[requestUrlString release], requestUrlString = nil;
[returnDataDic release], returnDataDic = nil;
[super dealloc];
}
- (id)initWithCityCode:(NSString *)aCityCode
requestURL:(NSString*)urlString
responseType:(SWEngineRequestType)theResponsetype
target:(id)theTarget
action:(SEL)theAction
{
if ((self = [super init]))
{
_isExecuting = NO;
_isFinished = NO;
target = theTarget;
action = theAction;
cityCode = [aCityCode retain];
requestUrlString = [urlString copy];
responseType = theResponsetype;
returnDataDic = [[NSMutableDictionary alloc] initWithCapacity:1];
if (cityCode)
{
[returnDataDic setObject:cityCode forKey:SWEATHER_CITYCODE];
}
[returnDataDic setObject:[NSNumber numberWithInt:responseType] forKey:SWEATHER_DOWNTYPE];
}
return self;
}
- (BOOL)isConcurrent
{
return YES;
}
- (void)finish
{
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
[connection release], connection = nil;
[responseData release],responseData = nil;
[cityCode release], cityCode = nil;
[requestUrlString release], requestUrlString = nil;
[returnDataDic release], returnDataDic = nil;
done = YES;
}
- (BOOL)isExecuting
{
return _isExecuting;
}
- (BOOL)isFinished
{
return _isFinished;
}
- (void)main
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
done = NO;
if ([self isCancelled])
{
[self willChangeValueForKey:#"isFinished"];
_isFinished = YES;
[self didChangeValueForKey:#"isFinished"];
[pool release];
return;
}
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
NSURL * urlToDownLoad = [NSURL URLWithString:[requestUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *request = [NSURLRequest requestWithURL:urlToDownLoad cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection)
{
responseData = [[NSMutableData alloc] init];
[connection start];
}
else
{
[self finish];
}
if (connection != nil)
{
do
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
while (!done);
}
[pool release], pool = nil;
}
#pragma mark -
#pragma mark - NSURLConnectionDataDelegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[returnDataDic setObject:#"error" forKey:...];
[target performSelectorOnMainThread:action withObject:returnDataDic waitUntilDone:NO];
[self finish];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[returnDataDic setObject:responseData forKey:...];
[target performSelectorOnMainThread:action withObject:returnDataDic waitUntilDone:NO];
[self finish];
}
#end
the instrument gave me a leak at: [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; Why? Thanks!
I just want to have a Asynchronous download at a operation but I use the NSAutoreleasePool then the instrument gave a leak at the:[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];.
Try putting your
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
in an autorelease pool.
What object did Instruments identify as having leaked? Where was it allocated? What was the stack trace?
When you run a run loop, all of the run loop sources and run loop observers may fire. So those few lines of code hide a near infinite set of possible things happening as the run loop runs. Any one of those may have a leak, or Instruments may be mistaken.
It is usually a bad idea to run the run loop in the default mode in an inner loop. It's not clear what you're trying to do with that loop, but generally you should schedule any of your own run loop sources in a private run loop mode and then run the run loop in that mode. That way, you're sure that only your own sources get run, which is usually what you want.
Related
My app crashes when I try to perform sent or cancel button actions in MFMailComposeViewController.
here is my code.
I have imported message framework and added delegates in .h file.
NSString *emailTitle = #"Test Email";
NSString *messageBody = #"Welcome Guest";
NSArray *recipentsArray = [[NSArray alloc]initWithObjects:#"xxx#gmail.com", nil];
[[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundColor:nil];
MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = self;
[mc setSubject:emailTitle];
[mc setMessageBody:messageBody isHTML:NO];
[mc setToRecipients:recipentsArray];
[self presentViewController:mc animated:YES completion:NULL];(void) mailComposeController:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"Mail cancelled");
break;
case MFMailComposeResultSaved:
NSLog(#"Mail saved");
break;
case MFMailComposeResultSent:
NSLog(#"Mail sent");
break;
case MFMailComposeResultFailed:
NSLog(#"Mail sent failure: %#", [error localizedDescription]);
break;
default:
break;
}
// Close the Mail Interface
[self dismissViewControllerAnimated:YES completion:NULL];
}
This is how my mf mail composer looks like :----
Just make the MFMailComposeViewController *mc in global.
I mean declare it outside this method. It's crashing because at the end of method Your mc gets deallocated.
Interface
#interface Demo()
{
MFMailComposeViewController *mc;
}
#end
Implementation
-(void)ShareViaEmail {
objMailComposeController = [[MFMailComposeViewController alloc] init];
objMailComposeController.mailComposeDelegate = self;
if ([MFMailComposeViewController canSendMail]) {
[objMailComposeController setSubject:#"Hello"];
[objMailComposeController setMessageBody:#"This is Body of Message" isHTML:NO];
NSData *ImageData = [NSData dataWithContentsOfFile:self.aStrSourceName];
NSString *mimeType;
if ([[self CheckExtensionOfURL:self.aStrSourceName]isEqualToString:#"Image"]) {
mimeType = #"image/png";
}
else if ([[self CheckExtensionOfURL:self.aStrSourceName]isEqualToString:#"PDF"]) {
mimeType = #"application/pdf";
} else if ([[self CheckExtensionOfURL:self.aStrSourceName]isEqualToString:#"Audio"]) {
mimeType = #"audio/mpeg";
} else if ([[self CheckExtensionOfURL:self.aStrSourceName]isEqualToString:#"Video"]) {
mimeType = #"video/mp4";
}
[objMailComposeController addAttachmentData:ImageData mimeType:mimeType fileName:#"attachement"];
}
[self.navigationController presentViewController:objMailComposeController animated:YES completion:Nil];
}
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
switch (result) {
case MFMailComposeResultCancelled:
[self ShowAlertView:kMsgMailCancelled];
break;
case MFMailComposeResultFailed:
[self ShowAlertView:kMsgMailFailed];
break;
case MFMailComposeResultSaved:
[self ShowAlertView:kMsgMailSaved];
break;
case MFMailComposeResultSent:
[self ShowAlertView:kMsgSent];
break;
default:
break;
}
// CHECK OUT THIS, THIS MIGHT BE IN YOUR CASE
[self.navigationController dismissViewControllerAnimated:controller completion:nil];
}
i have some problem with NSMutablearray and JSON parse.
So what i doing? A make parse from JSON and send to my TableViewCell.
I have my code:
h:
{
NSMutableData *webdata;
NSURLConnection *connection;
NSMutableArray *array;
NSMutableArray *array2;
NSTimer *timer;
}
m:
{
[super ViewDidload]
[[self tableTrack] setDelegate:self];
[[self tableTrack] setDataSource:self];
array = [[NSMutableArray alloc] init];
array2 = [[NSMutableArray alloc] init];
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(plistGet) userInfo:nil repeats:YES];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webdata setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webdata appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"error load");
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *allDataDictionary = [NSJSONSerialization JSONObjectWithData:webdata options:0 error:nil];
NSDictionary *playlist =[allDataDictionary objectForKey:#"playlist"];
for (NSDictionary *diction in playlist) {
NSDictionary *artist = [diction objectForKey:#"artist"];
NSDictionary *song = [diction objectForKey:#"song"];
NSString *name = [artist objectForKey:#"name"];
NSString *namesong = [song objectForKey:#"name"];
[array addObject:name];
[array2 addObject:namesong];
}
[[self tableTrack]reloadData];
}
-(void)plistGet {
[array removeAllObjects];
[array2 removeAllObjects];
NSURL *url = [NSURL URLWithString:#"http://plist.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
connection = [NSURLConnection connectionWithRequest:request delegate:self];
if (connection) {
webdata = [[NSMutableData alloc]init];
}
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [array count];
// return [array2 count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(! cell)
{
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]autorelease];
}
cell.textLabel.text = [array2 objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [array objectAtIndex:indexPath.row];
cell.textLabel.textColor = [UIColor colorWithRed:(50/255.0) green:(200/255.0) blue:(255/255.0) alpha:1];
[tableTrack setBackgroundView:nil];
tableTrack.backgroundColor = [UIColor clearColor];
cell.detailTextLabel.font=[UIFont fontWithName: #"Helvetica" size:11];
UIFont *myFont = [ UIFont fontWithName: #"Arial" size: 9.0 ];
cell.textLabel.font = myFont;
self.tableTrack.separatorStyle = UITableViewCellSeparatorStyleNone;
UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 43, 1024, 1)];
separatorView.layer.borderColor = [UIColor darkGrayColor].CGColor;
separatorView.layer.borderWidth = 0.5;
[cell.contentView addSubview:separatorView];
return cell;
}
All work very good but after 5 or 3 minutes i have error and my app crashed.
Error:
2013-06-21 12:32:41.502 EuropaPlusUA[651:707] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
* First throw call stack:
(0x353f188f 0x37798259 0x3533a9db 0xfa9d5 0x32e85efb 0x32e84fd9 0x32e84763 0x32e28f37 0x353501fb 0x32220aa5 0x322206bd 0x32224843 0x3222457f 0x3221c4b9 0x353c5b1b 0x353c3d57 0x353c40b1 0x353474a5 0x3534736d 0x36fe3439 0x32e53cd5 0xf8843 0xf87d0)
terminate called throwing an exception
What is it? Help please.
Your problem is that you probably do another plistget method after that 3-5 minutes. That method will throw away all objects from your array. During the time your data is getting loaded and the time you cleared your array, the table datasource is empty, however you are trying to get this object from index 0. This is why your crash happens.
The solution however is simple. Do not call the removeAllObjects method at all.
Simply replace the array with the contents that you will retrieve.
Replace mechanic that you will need to do the moment you get the data from your server:
NSMutableArray *tempDataArray = [[NSMutableArray alloc] init];
//put retrieved data from your web call in the tempDataArray
array = tempDataArray;
me thinks the only objectAtIndex is here.
cell.detailTextLabel.text = [array objectAtIndex:indexPath.row];
seems likely array was emptied by plistget
[array removeAllObjects];
Totumus Maximus is right.
If you just need to bridge the gap between getting clearing the arrays and reloading the data why not try NOT deleting them until the new data is ready? Then just replace them
Alternatively make a copy of them first (say to backUpArray and backUpArray2) and then check to see if you have data in array/array2 (something like if([array count]) or if (array) {...) before you try and load the cell.
If you have nothing in the arrays use [backUpArray lastObject] to give you some data for the (brief ?) time until the arrays are reloaded.
i have problem.
I have CityViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
TheatreController *tmpTheatreController = [storyboard instantiateViewControllerWithIdentifier:#"TheatreController"];
NSString *cityView = [[self.arrayCity objectAtIndex:indexPath.row] valueForKey:#"idCity"];
tmpTheatreController.cityView = cityView;
//[self.navigationController pushViewController:tmpTheatreController animated:YES];
[tmpTheatreController.tableView reloadData];
[self.delegate citiesViewControllerCancel:self];
}
When i select the city pass correctly the "idCity" in TheatreController.m
...
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"SelectCity"])
{
UINavigationController *nc = segue.destinationViewController;
CityViewController *mvc = [[nc viewControllers] objectAtIndex:0];
mvc.delegate = self;
}
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *webUrl = #"http://localhost:3000/theatres?city=";
webUrl = [webUrl stringByAppendingFormat:#"%#", cityView];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:webUrl]];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES]; });
}
- (void)fetchedData:(NSData *)responseData {
NSArray* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions error:nil];
NSMutableArray *theatreTMP = [[NSMutableArray alloc] initWithCapacity:[json count]];
int i = 0;
for (id object in [json valueForKeyPath:#"response.name"]) {
Theatres *t = [[Theatres alloc] init];
NSLog(#"JSON: %#", [[json valueForKeyPath:#"response.name"] objectAtIndex:i]);
t.theatre = [[json valueForKeyPath:#"response.name"] objectAtIndex:i];
t.idTheatre = [[json valueForKeyPath:#"response.id"] objectAtIndex:i];
[theatreTMP addObject:t];
i++;
}
self.arrayTheatre = [theatreTMP copy];
[self.tableView reloadData];
}
I have correctly the response of the server and all parameter are correct, but the problem i have with reloadData of the tableView main![enter image description here][1]. I dont see the update table.
HELP ME thanks
i have resolved with this solution
In the CityViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cityView = [[self.arrayCity objectAtIndex:indexPath.row] valueForKey:#"idCity"];
[self.delegate performSelector:#selector(reloadTable:) withObject:cityView];
[self.delegate citiesViewControllerCancel:self];
}
and in the TheatreTableView.m
- (void) callServer:(NSString *)idCity {
NSString *webUrl = #"http://localhost:3000/theatres?city=";
webUrl = [webUrl stringByAppendingFormat:#"%#", idCity];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:webUrl]];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];});
}
....
- (void) reloadTable:(id)idCity
{
[self callServer:idCity];
}
Thanks
I'm using
[NSURLConnection connectionWithRequest:req delegate:self];
and then I use
-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
-(void)connectionDidFinishLoading:(NSURLConnection *)connection;
to handle data loading. Everything is ok and working fine but I don't like the beauty of this code )
I wish to use blocks, to make my code looks like this:
[myConnection sendData:data
successBlock:^(void){NSLog(#"success");}
errorBlock:^(NSError * error){NSLog(#"error.description: %#", error.description);}];
is it possible to use NSURLConnection with blocks?
I use this class:
The MyConnection.h
#import <Foundation/Foundation.h>
#interface MyConnection : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
NSURLConnection * internalConnection;
NSMutableData * container;
}
-(id)initWithRequest:(NSURLRequest *)req;
#property (nonatomic,copy)NSURLConnection * internalConnection;
#property (nonatomic,copy)NSURLRequest *request;
#property (nonatomic,copy)void (^completitionBlock) (id obj, NSError * err);
-(void)start;
#end
And the MyConnection.m
#import "MyConnection.h"
static NSMutableArray *sharedConnectionList = nil;
#implementation MyConnection
#synthesize request,completitionBlock,internalConnection;
-(id)initWithRequest:(NSURLRequest *)req {
self = [super init];
if (self) {
[self setRequest:req];
}
return self;
}
-(void)start {
container = [[NSMutableData alloc]init];
internalConnection = [[NSURLConnection alloc]initWithRequest:[self request] delegate:self startImmediately:YES];
if(!sharedConnectionList)
sharedConnectionList = [[NSMutableArray alloc] init];
[sharedConnectionList addObject:self];
}
#pragma mark NSURLConnectionDelegate methods
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[container appendData:data];
}
//If finish, return the data and the error nil
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
if([self completitionBlock])
[self completitionBlock](container,nil);
[sharedConnectionList removeObject:self];
}
//If fail, return nil and an error
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if([self completitionBlock])
[self completitionBlock](nil,error);
[sharedConnectionList removeObject:self];
}
#end
to use it:
MyConnection * connection = [[MyConnection alloc]initWithRequest:req];
[connection setCompletitionBlock:^(id obj, NSError *err) {
if (!err) {
//It's ok, do domething with the response data (obj)
} else {
//There was an error
}
}];
[connection start];
It's based on the code, The Big Nerd Ranch uses on his book.
I hope it will be helpful.
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSLog(#"%#", response);
NSLog(#"%#", data);
}];
I need to wait for a response from a SOAP webservice, I am calling via a NSURLConnection as I need to manipulate the data being returned and then return it from my class to the calling class..
Here is my code:
#import <Foundation/Foundation.h>
#interface UsersBLL : NSObject {
NSMutableData *webData;
NSMutableString *soapResults;
NSXMLParser *xmlParser;
BOOL *recordResults;
NSNumber *EmailCount;
}
#property(nonatomic, retain) NSMutableData *webData;
#property(nonatomic, retain) NSMutableString *soapResults;
#property(nonatomic, retain) NSXMLParser *xmlParser;
-(int)checkEmailAddress:(NSString*)emailAddress;
#end
#import "UsersBLL.h"
#implementation UsersBLL
#synthesize webData;
#synthesize soapResults;
#synthesize xmlParser;
-(id)init {
self = [super init];
return self;
}
-(int)checkEmailAddress:(NSString*)emailAddress {
// Build the SOAP envelope
NSString *soapMessage = [NSString stringWithFormat:
#"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
"<soap:Body>\n"
"<CheckEmailAddress xmlns=\"http://tempuri.org/\">\n"
"<EmailAddress>%#</EmailAddress>\n"
"</CheckEmailAddress>\n"
"</soap:Body>\n"
"</soap:Envelope>\n", emailAddress];
NSLog(soapMessage);
NSURL *url = [NSURL URLWithString:#"http://photoswapper.mick-walker.co.uk/UsersService.asmx?op=CheckEmailAddress"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
NSString *msgLength = [NSString stringWithFormat:#"%d", [soapMessage length]];
[theRequest addValue: #"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[theRequest addValue: #"http://tempuri.org/CheckEmailAddress" forHTTPHeaderField:#"SOAPAction"];
[theRequest addValue: msgLength forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if( theConnection )
{
webData = [[NSMutableData data] retain];
}
else
{
NSLog(#"theConnection is NULL");
}
NSLog(#"%#", EmailCount);
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"ERROR with theConenction");
[connection release];
[webData release];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"DONE. Received Bytes: %d", [webData length]);
NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
NSLog(theXML);
[theXML release];
if( xmlParser )
{
[xmlParser release];
}
xmlParser = [[NSXMLParser alloc] initWithData: webData];
[xmlParser setDelegate: self];
[xmlParser setShouldResolveExternalEntities: YES];
[xmlParser parse];
[connection release];
[webData release];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName
attributes: (NSDictionary *)attributeDict
{
if( [elementName isEqualToString:#"CheckEmailAddressResult"])
{
if(!soapResults)
{
soapResults = [[NSMutableString alloc] init];
}
recordResults = TRUE;
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if( recordResults )
{
[soapResults appendString: string];
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if( [elementName isEqualToString:#"CheckEmailAddressResult"])
{
recordResults = FALSE;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc]init];
EmailCount = [formatter numberFromString:soapResults];
[formatter release];
[soapResults release];
soapResults = nil;
}
}
#end
CheckEmailAddress is declared as returning an integer value (I know it returns nothing in the sample above).
What I ideally want, is through the CheckEmailAddress method, return the value retrieved from the web service. However as the call NSURLConnection does not wait until the request has completed, I cannot do it.
I would be grateful if anyone could give me any potential ideas for workarounds.
The simplest solution would be using [NSURLConnection sendSynchronousRequest:returningResponse:error:].
It does not allow as much control as the approach you've taken, but is usually enough for most applications.
I have just posted a solution which wraps an asynchronous NSURLConnection to be able to block the calling thread. In case you need more control than the standard [NSURLConnection sendSynchronousRequest:returningResponse:error:] you can check out this link on StackOverflow:
NSURLConnection blocking wrapper implemented with semaphores
You have two choices:
Use +[NSURLConnection sendSynchronousRequest:returningResponse:error:]
Schedule the connection in a custom runloop mode, and run the loop in that mode until the data arrives or you have need to cancel the connection
It all depends on the level of asynchronism you need:
If it's OK to stay blocked during the whole request you may want to use
+[NSURLConnection sendSynchronousRequest:returningResponse:error:]
But, as suggested by Wade, be careful to add a timeout to your NSURLRequest, otherwise the connection might blocks and your application will hang.
If not, you can simply use the NSNotificationCenter. But you must be careful with race conditions over your data, specially if you are handling multiple requests