views:

1119

answers:

1

Hi,

I am having an issue with updating the contents of an "myInfoBox" object I created to be displayed while some background processes are done.

In the delegate method I am creating a new viewController:

-(void)loadMainView
{
        myFirstViewController = [[MyFirstViewController alloc] initWithNibName:@"MyFirstView" bundle:nil];     
        navigationController = [[UINavigationController alloc] initWithRootViewController:myFirstViewController];
        // myFirstViewController was retained again by the controller, release one
        [myFirstViewController release];
        navigationController.navigationBar.hidden = YES;
        [window addSubview:navigationController.view];
        [window makeKeyAndVisible];
        // the next method is run after the "viewDidLoad" is finished loading
        [myFirstViewController loadAlertViewForNewUser];
}

Following is my implementation of "myFirstViewController", it creates an instance of the "infoBox" class(I will show its code later):

- (void)viewDidLoad {

        self.navigationController.navigationBar.frame = CGRectMake(0, 0, 0, 0);
        self.navigationController.navigationBar.bounds = CGRectMake(0, 0, 0, 0);

        self.myInfoBox = [[InfoBoxController alloc] initWithNibName:@"InfoBox" bundle:[NSBundle mainBundle]];
        CGRect infoBoxFrame;
        infoBoxFrame = CGRectMake(60, 120, 200, 200);
        myInfoBox.view.frame = infoBoxFrame;

        myInfoBox.i_statusLabel.text = @"Downloading Account Updates";
        myInfoBox.i_titleLabel.text = @"Updating";
// disabled for testing
        //myInfoBox.view.hidden = YES;
        [self.view addSubview:myInfoBox.view];
        [super viewDidLoad];
    }

// this method is called after the view has been loaded by the delegate
- (void)loadAlertViewForNewUser
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Welcome!" message:@"Connect to download stuff from your account?"
                  delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
    alert.tag = 0;
    [alert show];
}

// implementation of the alertview delegate
- (void)alertView:(UIAlertView *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (actionSheet.tag == 0)
    {
     if (buttonIndex == 0) 
     { NSLog(@"button 0 was pressed"); }
     if (buttonIndex == 1) 
     {
// this is the button that is pressed
      [actionSheet removeFromSuperview];
      [actionSheet release];

// tried using this also
      //[self performSelectorOnMainThread:@selector(userInitialSetupMainThread) withObject:nil waitUntilDone:NO];
// do stuff and update the infobox about it
      [self loadInfoBoxInitialUserSetup];
// tried using this as well
      //[self performSelectorInBackground:@selector(loadInfoBoxInitialUserSetup) withObject:nil];
     }
     return;
    }
}

- (void)loadInfoBoxInitialUserSetup
{
    [self performSelectorOnMainThread:@selector(userInitialSetupMainThread) withObject:nil waitUntilDone:NO];
}

- (void)userInitialSetupMainThread
{
    // fetch JSON data
    NSDictionary *responseJSON = [NSDictionary dictionaryWithDictionary:[self getUserstuff]];

    self.myInfoBox.i_statusLabel.text = @"Processing Recieved information";
// breakpoint - nothing changes in the view on the simulator
    [myInfoBox.view setNeedsLayout];
// breakpoint - nothing changes in the view on the simulator
    [myInfoBox.view setNeedsDisplay];
// breakpoint - nothing changes in the view on the simulator
    [myInfoBox.parentViewController.view setNeedsLayout];
// breakpoint - nothing changes in the view on the simulator
    [myInfoBox.parentViewController.view setNeedsDisplay];
// breakpoint - nothing changes in the view on the simulator
    [myInfoBox performSelectorOnMainThread:@selector(updateValuesForTitle:) withObject:@"test" waitUntilDone:YES];
// breakpoint - nothing changes in the view on the simulator
    [self.view setNeedsLayout];
// breakpoint - nothing changes in the view on the simulator
    [self.view setNeedsDisplay];
// breakpoint - nothing changes in the view on the simulator
    self.myInfoBox.i_statusLabel.text = @"Reloading...";  
// breakpoint - nothing changes in the view on the simulator
    [self readStuffFromDB]; 
    sleep(2);
//disabled view removal for testing..
    //[self.myInfoBox.view removeFromSuperview];
// breakpoint - nothing changes in the view on the simulator
}

What happens for me in the testing is that the myInfoBox object is created on screen when the -(void)loadMainView method is complete, then I can see on screen the "myInfoBox" in the background while the alertView in front (for testing...) at this point the screen is responsive and I can select the YES, once I select yes the delegate method is called. As I commented in the source file, using breakpoints I am monitoring the simulator and following the code, never the less the changed label values are not reflected while I am still in the - (void)userInitialSetupMainThread method, but once it finishes the view updates with the latest set .text value!! grrr..

Also, the source for the myInfoBox class:

@interface InfoBoxController : UIViewController {
    IBOutlet UILabel* i_titleLabel;
    IBOutlet UILabel* i_statusLabel;
    IBOutlet UIImageView* i_loadingImage;
    IBOutlet UIImageView* i_background;
    IBOutlet UIActivityIndicatorView* i_activityIndicator;
}

@property(nonatomic, retain) IBOutlet UILabel* i_titleLabel;
@property(nonatomic, retain) IBOutlet UILabel* i_statusLabel;
@property(nonatomic, retain) IBOutlet UIImageView* i_loadingImage;
@property(nonatomic, retain) IBOutlet UIImageView* i_background;
@property(nonatomic, retain) IBOutlet UIActivityIndicatorView* i_activityIndicator;

//- (void)updateValuesForTitle:(NSString *)title Label:(NSString *)label;
- (void)updateValuesForTitle:(NSString *)title;

@end

@implementation InfoBoxController

@synthesize i_titleLabel, i_statusLabel, i_loadingImage, i_background;
@synthesize i_activityIndicator;

//-(void)updateValuesForTitle:(NSString *)title Label:(NSString *)label
-(void)updateValuesForTitle:(NSString *)title
{
    self.i_titleLabel.text = title;
    self.i_statusLabel.text = title;
    [self.i_titleLabel setNeedsDisplay];
    [self.i_statusLabel setNeedsDisplay];
}

Sorry for the LOONG post :) PLEASE ASSIST!

+2  A: 

At the risk of sounding unhelpful, that's kind of just how it works. If you have long-running code in the main event loop (i.e., you don't explicitly create a thread or similar), the operating system won't be able to update the UI.

To update the UI while your code is running, you either need to run your complex operation in the back ground using thread, NSOperationQueue, etc, or just break it into smaller steps and return control to the main loop occasionally so that the UI can be updated.

Stephen Darlington
THANKS!!You gave me an idea, I ran "- (void)userInitialSetupMainThread" in a background process and then using the [myInfoBox performSelectorOnMainThread:@selector(updateValuesForTitle:) withObject:@"test" waitUntilDone:YES];did the trick!!Thanks for the quick reply!
Romansky