Представление, загруженное из пера, не будет обновлять содержимое UILabel при запуске в методе - PullRequest
4 голосов
/ 13 июля 2009

У меня проблема с обновлением содержимого объекта «myInfoBox», который я создал для отображения во время выполнения некоторых фоновых процессов.

В методе делегата я создаю новый 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];
}

Ниже приведена моя реализация myFirstViewController, он создает экземпляр класса "infoBox" (я покажу его код позже):

- (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
}

Что происходит со мной в тестировании, так это то, что объект myInfoBox создается на экране после завершения метода - (void) loadMainView, а затем я вижу на экране «myInfoBox» в фоновом режиме, в то время как alertView впереди (для тестирование ...) на этом этапе экран отзывчивый, и я могу выбрать ДА, как только я выберу «да», вызывается метод делегата. Как я прокомментировал в исходном файле, используя контрольные точки, я слежу за симулятором и следую за кодом, тем не менее измененные значения меток не отражаются, пока я все еще в методе - (void) userInitialSetupMainThread, но как только он заканчивает обновления представления с последним установленным значением .text !! гррр ..

Также источник для класса myInfoBox:

@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];
}

Извините за ПОЛНЫЙ пост :) ПОЖАЛУЙСТА, ПОМОГИТЕ!

1 Ответ

2 голосов
/ 13 июля 2009

Риск звучит бесполезно, вот как это работает. Если в главном цикле событий имеется долго выполняемый код (т. Е. Вы явно не создаете поток или аналогичный), операционная система не сможет обновить пользовательский интерфейс.

Чтобы обновить пользовательский интерфейс во время выполнения кода, вам нужно либо выполнить сложную операцию на заднем плане, используя поток, NSOperationQueue и т. Д., Либо просто разбить ее на более мелкие шаги и периодически возвращать управление в основной цикл, что пользовательский интерфейс может быть обновлен.

...