简体   繁体   中英

NSOperationQueue avoids pushing view controller into navigation controller stack?

I have a view controller that is sub class of UIViewController which has table view into it and each rows in table view is linked to distinct xml url. I made a parser class that is sub class of NSOperation and implemented methods to parse the XML file on selection of each row as,

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    [self performSelectorOnMainThread:@selector(pushView) withObject:nil waitUntilDone:NO];
    [self performSelectorInBackground:@selector(parseOperation:) withObject:indexPath];
}

- (void)pushView {
    detailView = [[viewDetailsController alloc] initWithNibName:@"viewDetailsController" bundle:nil];
    [self.navigationController pushViewController:detailView animated:YES]; 
}

 - (void)parseOperation:(NSIndexPath *)indexPath {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    self.queue = [[NSOperationQueue alloc] init];
    parserClass *parser = [[parserClass alloc] initWithParseUrl:[[self.arrayOfUrls objectAtIndex:indexPath.row]delegate:self];
    [queue addOperation:parser];
    [parser release];
    [pool release];
}

Parser works great but in its custom delegate method I have called to push view controller on the top of the navigation controller stack, the view controller initializes correctly but the new view controller is not pushed into the screen.

I have edited the question for using the main thread and background thread while the background thread works correctly for parsing the main thread just initializes and does not push view controller. What is the problem ?

You need to push the view controller(s) on the main thread. Use performSelectorOnMainThread:withObject:waitUntilDone: to invoke a method on the main thread.

If there is a possibility that you will push multiple view controllers, your app will crash if a view controller is pushed onto the stack while another is being animated in. In this case, you should either specify animated:NO , or collect the view controllers in an NSArray and use setViewControllers:animated: to add them to the stack.


In response to your updated question: You shouldn't need to call parseOperation: via performSelectorInBackground:withObject: since the NSOperationQueue will execute the NSOperation that it creates in a separate thread anyway. I suggest adding a delegate property to your NSOperation subclass and following this pattern:

MyViewController.m :

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyParseOperation *parseOp = ...
    parseOp.delegate = self;
    [myOperationQueue addOperation:parseOp];
}

// Called by MyParseOperation
- (void)operationCompletedWithXML:(XML *)parsedXML
{
    // Use parsedXML to create and configure a view controller
    MyCustomViewController *vc = ...

    // Animation is OK since only one view controller will be created
    [self.navigationController pushViewController:vc animated:YES];
}

MyParseOperation.m :

// Call this method once the XML has been parsed
- (void)finishUp
{
    // Invoke delegate method on the main thread
    [self.delegate performSelectorOnMainThread:@selector(operationCompletedWithXML:) withObject:self.parsedXML waitUntilDone:YES];

    // Perform additional cleanup as necessary
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM