I am using NSOperationQueue & NSInvocationOperation to call a method on my UIViewController which then calls a method in another class which, in turn, parses an XML file from the web and updates some Core Data Managed Objects.
This process works when I run the application first, but when I call the method for the second time (when the UIViewController is shown again), it doesn't execute any lines after the executeFetchRequest statement in the XML parser classs. Here's the code I am using to execute:
I have a UITableViewController that takes all the static information for the carparks from my Core Data store when it loads:
- (void)viewDidLoad
{
NSLog(@"viewDidLoad");
[super viewDidLoad];
southeastCarparks = [[NSMutableArray alloc] init];
southwestCarparks = [[NSMutableArray alloc] init];
northeastCarparks = [[NSMutableArray alloc] init];
northwestCarparks = [[NSMutableArray alloc] init];
carparkLocations = [[NSMutableArray alloc] initWithObjects:southeastCarparks, southwestCarparks, northeastCarparks, northwestCarparks, nil];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:@"CarparkInfo" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
self.carparkInfos = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (CarparkInfo *carpark in self.carparkInfos){
if ([carpark.details.region isEqualToString:@"Southeast"]){
[southeastCarparks addObject:carpark];
} else if ([carpark.details.region isEqualToString:@"Southwest"]){
[southwestCarparks addObject:carpark];
} else if ([carpark.details.region isEqualToString:@"Northeast"]){
[northeastCarparks addObject:carpark];
} else if ([carpark.details.region isEqualToString:@"Northwest"]){
[northwestCarparks addObject:carpark];
}
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(loadXMLData)
name:@"appDidBecomeActive"
object:nil];
}
Then when the view appears I call the loadXML method to go to the web and get the latest parking space information from an xml file
- (void) viewDidAppear:(BOOL)animated
{
[self loadXMLData];
NSLog(@"viewDidAppear");
}
- (void) loadXMLData {
NSLog(@"loadXMLData");
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(loadXMLDataWithOperation)
object:nil];
[queue addOperation:operation];
}
- (void) loadXMLDataWithOperation {
xmlParser = [[XMLParser alloc] loadXMLByURL:xmlFileURL];
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
}
In the XMLParser class, I take the xmlFileURL passed in, retrieve it from the web, parse it and then attempt to update the available spaces in the Core Data store
-(id) loadXMLByURL:(NSString *)urlString
{
_carparks = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if (![elementName isEqualToString:@"carpark"]){
return;
}
currentCarpark = [Carpark alloc];
NSString *name = [attributeDict objectForKey:@"name"];
currentCarpark.name = name;
NSString *spaces = [attributeDict objectForKey:@"spaces"];
currentCarpark.spaces = spaces;
[self.carparks addObject:currentCarpark];
currentCarpark = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// set up the managedObjectContext to read data from CoreData
id delegate = [[UIApplication sharedApplication] delegate];
self.managedObjectContext = [delegate managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription
entityForName:@"CarparkInfo" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"code=%@",name]];
NSError *error;
CarparkInfo *cgCarpark;
// THIS IS THE LAST LINE TO BE EXECUTED THE 2ND TIME AROUND. THE APPLICATION DOESN'T THROW AN ERROR BUT DOESN'T GO ON TO UPDATE THE CARPARK OBJECT ON THE LINE AFTER
cgCarpark = [[self.managedObjectContext executeFetchRequest:fetchRequest error:&error] lastObject];
cgCarpark.availableSpaces = spaces;
error = nil;
if (![self.managedObjectContext save:&error]) {
//Handle any error with the saving of the context
}
}
Am I doing something wrong in the way I am using the Managed Object Context?
Thanks in advance for any help