iphone – 从nib加载的视图在方法中运行时不会更新UILabel的内容

我有一个问题是更新我创建的“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
}

在测试中我发生的事情是,当 – (void)loadMainView方法完成时,myInfoBox对象在屏幕上创建,然后我可以在屏幕上看到后面的alertView中的“myInfoBox”(用于测试.. .)此时屏幕响应,我可以选择YES,一旦我选择是,则调用委托方法.
正如我在源文件中所评论的那样,使用断点我正在监视模拟器并遵循代码,当我仍然在 – (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];
}

对不起,LOONG帖子:)
请协助!

最佳答案 听起来无益的风险,这就是它的工作方式.如果在主事件循环中有长时间运行的代码(即,您没有显式创建线程或类似代码),则操作系统将无法更新UI.

要在你的代码运行时更新UI,您可能需要使用线程,NSOperationQueue,等在后面的地面上运行复杂的操作,或者只是把它分解成更小的步骤,并将控制返回到主循环偶尔从而UI可以更新.

点赞