问题
I am an iOS developer currently developing an iphone application. I have a simple question regarding updating the contents of a ViewController and I would greatly appreciate it if I can get someone’s feedback who is aware of this issue or have a suggested solution.
I’m writing a method that constantly updates the text of a label (and other components such as the background colour of a UIImage “box1” and “box2” ).
The issue : update to the text of the label (along with other changes) only takes effect at the end when the code was done execution. So I have written a simple infinite loop that does this as follows:
-(void) stateTest{
int i=0;
for(;;){
if (i==5) {
self.stateLabel.text=@"Opened"; //stateLabel previously declared
[self.box2 setBackgroundColor:[UIColor whiteColor]]; // box2 declared as UIImage
[self.box1 setBackgroundColor:[UIColor purpleColor]];
}
if (i==10){
self.stateLabel.text=@"Closed";
[self.box2 setBackgroundColor:[UIColor redColor]];
[self.box1 setBackgroundColor:[UIColor whiteColor]];
break;
}
i++;
}
}
and in the viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
self.stateLabel.text=@“View did Load";
[self.box1 setBackgroundColor:[UIColorwhiteColor]];
[self.box2 setBackgroundColor:[UIColorwhiteColor]];
[self stateTest];
}
I’m stepping through the code (breakpoints) and this is the issue I’m facing:
- when i==5 the label text does NOT get updated (same as the color of the boxes)
- when i==10, the label text does NOT get updated
- The update (both the label text and the box color) show up after the code is done executing with stateLabel : "Closed", Box 2: red background color
I have tried calling upon several functions at the end of the stateTest method (after the i++) hoping that it will “REFRESH” the contents of the view, label and/or the UIImage:
[self.stateLabel setNeedsLayout];
[self.stateLabel setNeedsDisplay];
[self.box1 setNeedsDisplay];
[self.box2 setNeedsDisplay];
[self.view setNeedsDisplay];
Unfortunately non of these trials worked. I have also put an NSLog that outputs the text of the label and that works just fine, as I want. But the problem is with the dynamic update of the contents of the view controller during execution of code/method.
I would greatly appreciate any help and I am open to any suggestion
Ideally, this code is used in parallel with a face detection algorithm that detects the state of the mouth. There is a processImage method that processes the image every frame. I call [self stateTest] every time the image is processed; if the mouth is opened → stateLabel.text=@”Open”…etc
Thank you in advance for your contribution Cheers!
回答1:
The UI update will happen only when the run loop is completed. normally i run the infinite loop in background thread and post the UI update in the main thread. This will take care of the run loop.
Below code is for reference.
-(void) viewDidLoad
{
[super viewDidLoad];
self.subView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 30, 30)];
self.subView.backgroundColor = [UIColor blueColor];
[self.view addSubview:self.subView];
dispatch_queue_t newQueue = dispatch_queue_create("newQueue", nil);
dispatch_async(newQueue, ^{
[self stateTest];
});
}
-(void) stateTest{
int i=0;
for(;;){
if (i==5) {
[self performSelectorOnMainThread:@selector(purpleColor) withObject:self waitUntilDone:NO];
}
if (i==10){
[self performSelectorOnMainThread:@selector(blueColor) withObject:self waitUntilDone:NO];
// break;
}
if (i==15){
[self performSelectorOnMainThread:@selector(redColor) withObject:self waitUntilDone:NO];
//break;
}
if (i==20){
[self performSelectorOnMainThread:@selector(greenColor) withObject:self waitUntilDone:NO];
break;
}
sleep(1);
i++;
}
}
-(void) purpleColor
{
[self.subView setBackgroundColor:[UIColor purpleColor]];
}
-(void) blueColor
{
[self.subView setBackgroundColor:[UIColor blueColor]];
}
-(void) redColor
{
[self.subView setBackgroundColor:[UIColor redColor]];
}
-(void) greenColor
{
[self.subView setBackgroundColor:[UIColor greenColor]];
}
回答2:
it's not a very good idea to run a infinite loop on the main thread (uithread). Instead can I suggest you to use a timer or a dispatch event ? below is some code you can use for a timer. and I would also point you out that NSTimer cannot be re used. hence if you wish to do this operation after you invalidated it you need to re create the timer & add it into a runloop.
// properties in your controller
@property (nonatomic) BOOL state;
@property (nonatomic, strong) NSTimer *timer;
// where to create it . timer interval is in seconds & use decimals if you want split seconds.
- (void)viewDidLoad
{
[super viewDidLoad];
self.timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(onTimer:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
}
// timer callback method
int count = 0;
- (void)onTimer:(NSNotification *)sender
{
self.state = !self.state;
if (self.state)
{
self.box1.backgroundColor = [UIColor redColor];
self.box2.backgroundColor = [UIColor blueColor];
}
else
{
self.box1.backgroundColor = [UIColor yellowColor];
self.box2.backgroundColor = [UIColor greenColor];
}
count++;
if (count == 100)
{
[self.timer invalidate];
[[[UIAlertView alloc] initWithTitle:@"timer done" message:@"timer finished" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];
}
}
来源:https://stackoverflow.com/questions/23946588/updating-label-text-dynamically-while-executing-another-method