Reputation: 1555
I use this piece of code to create some NSOperations and add them to a queue:
HUD = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
//HUD.labelText = @"Downloading..";
//HUD.dimBackground = YES;
/* Operation Queue init */
NSOperationQueue *queue = [NSOperationQueue new];
// Spawn request operations & add them to queue
SoapRequestOperation *operation = [[SoapRequestOperation alloc] initWithRequest:@"<?xml version=\"1.0\" encoding=\"utf-8\"?> <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/\"> <soap:Body> <Categories xmlns=\"http://tempuri.org/\"> <UID>string</UID> <Username>string</Username> <Password>string</Password> </Categories> </soap:Body> </soap:Envelope>" andValue:@"Categories"];
[queue addOperation:operation];
operation = [[SoapRequestOperation alloc] initWithRequest:@"<?xml version=\"1.0\" encoding=\"utf-8\"?> <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/\"> <soap:Body> <Currencies xmlns=\"http://tempuri.org/\"> <UID>string</UID> <Username>string</Username> <Password>string</Password> </Currencies> </soap:Body> </soap:Envelope>" andValue:@"Currencies"];
[queue addOperation:operation];
operation = [[SoapRequestOperation alloc] initWithRequest:@"<?xml version=\"1.0\" encoding=\"utf-8\"?> <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/\"> <soap:Body> <Nominals xmlns=\"http://tempuri.org/\"> <UID>string</UID> <Username>string</Username> <Password>string</Password> </Nominals> </soap:Body> </soap:Envelope>" andValue:@"Nominals"];
[queue addOperation:operation];
operation = [[SoapRequestOperation alloc] initWithRequest:@"<?xml version=\"1.0\" encoding=\"utf-8\"?> <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/\"> <soap:Body> <Projects xmlns=\"http://tempuri.org/\"> <UID>string</UID> <Username>string</Username> <Password>string</Password> </Projects> </soap:Body> </soap:Envelope>" andValue:@"Projects"];
[queue addOperation:operation];
operation = [[SoapRequestOperation alloc] initWithRequest:@"<?xml version=\"1.0\" encoding=\"utf-8\"?> <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/\"> <soap:Body> <Register xmlns=\"http://tempuri.org/\"> <UID>string</UID> <Username>string</Username> <Password>string</Password> <OrganisationCode>string</OrganisationCode> </Register> </soap:Body> </soap:Envelope>" andValue:@"Register"];
[queue addOperation:operation];
[queue waitUntilAllOperationsAreFinished];
[self reloadTableData];
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"37x-Checkmark.png"]];
HUD.mode = MBProgressHUDModeCustomView;
[HUD hide:YES afterDelay:2];
This is the .m file for my NSOperation subclass:
#import "SoapRequestOperation.h"
#import "Currency.h"
#import "Category.h"
#import "Project.h"
#import "Constants.h"
@implementation SoapRequestOperation
@synthesize request, value;
-(id) initWithRequest:(NSString *)l_Request andValue:(NSString *)l_Value{
if (self = [super init]) {
/* do most of initialization */
self.request = l_Request;
self.value = l_Value;
xmlBlock = 0;
appDelegate = [[UIApplication sharedApplication] delegate];
}
return(self);
}
- (void) main {
if ([value isEqualToString:@"Category"]){
xmlBlock = CATEGORY;
}
else if ([value isEqualToString:@"Currency"]){
xmlBlock = CURRENCY;
}
else if ([value isEqualToString:@"Nominal"]){
xmlBlock = NOMINAL;
}
else if ([value isEqualToString:@"Project"]){
xmlBlock = PROJECT;
}
else {
xmlBlock = REGISTER;
}
NSString *soapMsg = request;
//---print it to the Debugger Console for verification---
NSLog(@"%@", soapMsg);
NSURL *url = [NSURL URLWithString:
@"http://www.$^$%£%@%^£.co.uk/$$^$^£$^£.asmx"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
//---set the headers---
NSString *msgLength = [NSString stringWithFormat:@"%d",
[soapMsg length]];
[req addValue:@"text/xml; charset=utf-8"
forHTTPHeaderField:@"Content-Type"];
[req addValue:[NSString stringWithFormat:@"http://tempuri.org/%@", value]
forHTTPHeaderField:@"SOAPAction"];
[req addValue:msgLength forHTTPHeaderField:@"Content-Length"];
//---set the HTTP method and body---
[req setHTTPMethod:@"POST"];
[req setHTTPBody: [soapMsg dataUsingEncoding:NSUTF8StringEncoding]];
//[activityIndicator startAnimating];
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if (conn) {
webData = [NSMutableData data];
}
}
-(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 {
}
-(void) connectionDidFinishLoading:(NSURLConnection *) connection {
NSLog(@"DONE. Received Bytes: %d", [webData length]);
NSString *theXML = [[NSString alloc]
initWithBytes: [webData mutableBytes]
length:[webData length]
encoding:NSUTF8StringEncoding];
//---shows the XML---
NSLog(@"%@", theXML);
xmlParser = [[NSXMLParser alloc] initWithData: webData];
[xmlParser setDelegate: self];
[xmlParser setShouldResolveExternalEntities:YES];
[xmlParser parse];
}
//---when the start of an element is found---
-(void) parser:(NSXMLParser *) parser
didStartElement:(NSString *) elementName
namespaceURI:(NSString *) namespaceURI
qualifiedName:(NSString *) qName
attributes:(NSDictionary *) attributeDict {
currentElement = [elementName copy];
//Category
if( [currentElement isEqualToString:@"Item"])
{
category = [[NSMutableDictionary alloc] init];
categoryName = [[NSMutableString alloc] init];
}
//Currency
if ([currentElement isEqualToString: @"Currency"]) {
currency = [[NSMutableDictionary alloc] init];
countryName = [[NSMutableString alloc] init];
currencyName = [[NSMutableString alloc] init];
currencyUnit = [[NSMutableString alloc] init];
shortName = [[NSMutableString alloc] init];
}
//Nominal
if( [currentElement isEqualToString:@"Nominal"])
{
nominal = [[NSMutableDictionary alloc] init];
name = [[NSMutableString alloc] init];
description = [[NSMutableString alloc] init];
paid = [[NSMutableString alloc] init];
}
//Project
if( [currentElement isEqualToString:@"Project"])
{
project = [[NSMutableDictionary alloc] init];
projectName = [[NSMutableString alloc] init];
projectDescription = [[NSMutableString alloc] init];
}
//Register
if( [currentElement isEqualToString:@"RegisterResult"])
{
elementFound = YES;
}
}
-(void)parser:(NSXMLParser *) parser foundCharacters:(NSString *)string
{
//Category
if (xmlBlock == CATEGORY){
if ([currentElement isEqualToString: @"Item"]){
[categoryName appendString:string];
}
}
//Currency
if (xmlBlock == CURRENCY){
if ([currentElement isEqualToString: @"CountryName"]){
[countryName appendString:string];
}
else if ([currentElement isEqualToString: @"CurrencyName"]){
[currencyName appendString:string];
}
else if ([currentElement isEqualToString: @"Unit"]){
[currencyUnit appendString:string];
}
else if ([currentElement isEqualToString: @"ShortName"]){
[shortName appendString:string];
}
}
//Nominal
if ([currentElement isEqualToString: @"Name"] && xmlBlock == NOMINAL){
[name appendString:string];
}
else if ([currentElement isEqualToString: @"Description"] && xmlBlock == NOMINAL){
[description appendString:string];
}
else if ([currentElement isEqualToString: @"Paid"]){
[paid appendString:string];
}
//Project
if (xmlBlock == PROJECT) {
if ([currentElement isEqualToString: @"Name"]){
[projectName appendString:string];
}
else if ([currentElement isEqualToString: @"Description"]){
[projectDescription appendString:string];
}
}
//Register
if (xmlBlock == REGISTER && elementFound){
registerVal = string;
}
}
//---when the end of element is found---
-(void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"Item"])
{
// save values to an item, then store that item into the array...
[category setObject:categoryName forKey:@"categoryName"];
[categories addObject:[category copy]];
Category *c = [[Category alloc] init];
c.categoryName = categoryName;
c.totalValue = @"0.00";
[appDelegate.categories addObject:c];
NSLog(@"%d", [appDelegate.categories count]);
}
//Currency
if ([elementName isEqualToString: @"Currency"]) {
// save values to an item, then store that item into the array...
[currency setObject:countryName forKey:@"countryName"];
[currency setObject:currencyName forKey:@"currencyName"];
[currency setObject:currencyUnit forKey:@"unit"];
[currency setObject:shortName forKey:@"shortName"];
[currencies addObject:[currency copy]];
Currency *c = [[Currency alloc] init];
c.totalValue = @"0.00";
c.countryName = countryName;
c.currencyName = currencyName;
double myDouble = [currencyUnit doubleValue];
c.unit = myDouble;
c.shortName = shortName;
[appDelegate.currencies addObject:c];
NSLog(@"%d", [appDelegate.currencies count]);
}
//Nominal
if ([elementName isEqualToString:@"Nominal"])
{
// save values to an item, then store that item into the array...
[nominal setObject:name forKey:@"name"];
[nominal setObject:description forKey:@"description"];
[nominal setObject:paid forKey:@"paid"];
[nominals addObject:[nominal copy]];
NSLog(@"%d", [nominals count]);
}
if ([elementName isEqualToString:@"Project"])
{
// save values to an item, then store that item into the array...
[project setObject:projectName forKey:@"projectName"];
[project setObject:projectDescription forKey:@"projectDescription"];
[projects addObject:[project copy]];
Project *p = [NSEntityDescription
insertNewObjectForEntityForName:@"Project"
inManagedObjectContext:appDelegate.managedObjectContext];
[p setValue:projectName forKey:@"name"];
[p setValue:@"0.00" forKey:@"totalValue"];
NSError *error;
if (![appDelegate.managedObjectContext save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
[appDelegate.projects addObject:p];
NSLog(@"%d", [appDelegate.currencies count]);
}
if ([elementName isEqualToString:@"RegisterResult"])
{
if ([registerVal isEqualToString:@"true"]){
boolRegister = YES;
}
else {
boolRegister = NO;
}
NSLog(@"BOOL = %@", (boolRegister ? @"YES" : @"NO"));
elementFound = FALSE;
}
}
Unfortunately, the NSURLConnection and NSXMLParser delegate methods are not being called (everything is as it should be in the header file). And I'm not sure I fully understand the line:
[queue waitUntilAllOperationsAreFinished];
Should this not cause the calling thread to wait until all the operations are completed? I have a feeling this line isn't working due to the faults with the NSOperation subclass itself?
Can anyone help me out here?
Thanks a lot,
Jack
Upvotes: 0
Views: 1151
Reputation: 26383
Joel is correct in the start
method you should call the main
method to be start on the main thread, or you need to keep alive the thread in wich the method id called.
Upvotes: 0
Reputation: 16134
The issue is how you have setup your operation. It is setup as a non-concurrent operation so it is executing the main method in a separate thread then finishing up. By the time the delegates are called, the thread is gone. Poof. Your issue is you are not keeping the thread around. See here: How do I do an Asychronous NSURLConnection inside an NSOperation?
Upvotes: 2