Обновление текста метки (динамически) при выполнении другого метода

Я разработчик iOS, в настоящее время разрабатываю приложение для iphone. У меня есть простой вопрос об обновлении содержимого ViewController, и я был бы очень признателен, если бы я мог получить отзыв от кого-то, кто знает об этой проблеме или предлагает решение.

Я пишу метод, который постоянно обновляет текст метки (и другие компоненты, такие как цвет фона UIImage «box1» и «box2»).

Проблема: обновление текста метки (наряду с другими изменениями) вступает в силу только в конце, когда код выполнен. Итак, я написал простой бесконечный цикл, который делает это следующим образом:

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

}

и в методе viewDidLoad:

- (void)viewDidLoad
{       
    [super viewDidLoad];
    self.stateLabel.text=@“View did Load";
    [self.box1 setBackgroundColor:[UIColorwhiteColor]];
    [self.box2 setBackgroundColor:[UIColorwhiteColor]];   
    [self stateTest];

}

Я просматриваю код (точки останова), и вот проблема, с которой я столкнулся:

  1. когда i==5 текст метки НЕ обновляется (такой же, как цвет полей)
  2. когда i==10, текст метки НЕ обновляется
  3. Обновление (как текст метки, так и цвет поля) отображается после выполнения кода с помощью stateLabel : "Closed", поле 2: красный цвет фона

Я попытался вызвать несколько функций в конце метода stateTest (после i++), надеясь, что он «ОБНОВИТ» содержимое представления, метки и/или UIImage:

    [self.stateLabel setNeedsLayout];
    [self.stateLabel setNeedsDisplay];
    [self.box1 setNeedsDisplay];
    [self.box2 setNeedsDisplay];
    [self.view setNeedsDisplay];

К сожалению, ни одно из этих испытаний не сработало. Я также поставил NSLog, который выводит текст метки, и он отлично работает, как я и хотел. Но проблема заключается в динамическом обновлении содержимого контроллера представления во время выполнения кода/метода.

Я был бы очень признателен за любую помощь, и я открыт для любого предложения

В идеале этот код используется параллельно с алгоритмом распознавания лиц, определяющим состояние рта. Существует метод processImage, который обрабатывает изображение каждый кадр. Я вызываю [self stateTest] каждый раз, когда обрабатывается изображение; если рот открыт → stateLabel.text=@”Open”… и т.д.

Заранее спасибо за ваш вклад Ура!


person Tamimi    schedule 30.05.2014    source источник
comment
Пользовательский интерфейс визуализируется только один раз за итерацию цикла выполнения. Кроме того, учтите, что частота обновления экрана современного iPhone составляет около 60 кадров в секунду. Вы пройдете через пять итераций простого цикла намного быстрее, чем экран сможет физически обновиться. Но несмотря на это, основной цикл выполнения в приложении для iOS в значительной степени управляется событиями, и вы должны думать с точки зрения написания кода для реагирования на события (включая, возможно, истечение обратного отсчета).   -  person Carl Veazey    schedule 30.05.2014


Ответы (2)


Обновление пользовательского интерфейса произойдет только после завершения цикла выполнения. обычно я запускаю бесконечный цикл в фоновом потоке и публикую обновление пользовательского интерфейса в основном потоке. Это позаботится о цикле выполнения.

Ниже приведен код для справки.

    -(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]];
    }
person Naveen Prasad R    schedule 30.05.2014
comment
Спасибо за ваше предложение, оно действительно имело большое значение! Просто быстрый вопрос, приведет ли [self PerformSelector..] к тому же результату? И под этим я подразумеваю, выполняет ли он метод в основном потоке? Если это не так, в чем преимущества вызова метода с помощью PerformSelecor по сравнению с обычным вызовом метода: [self method]? Спасибо - person Tamimi; 30.05.2014
comment
Селектор выполнения отправит объекту сообщение, подобное [методу self]. Существуют различные перегруженные селекторы выполнения, которые помогают достичь многих целей, кроме вызова метода. Например. Метод может быть вызван после задержки. В нашем случае, поскольку мы обновляем пользовательский интерфейс, это необходимо опубликовать в основном потоке. Поэтому я использовал PerformSelectorOnMainThread, чтобы заставить селектор выполняться в основном потоке. - person Naveen Prasad R; 30.05.2014

не очень хорошая идея запускать бесконечный цикл в основном потоке (uthread). Вместо этого я могу предложить вам использовать таймер или событие отправки? ниже приведен код, который вы можете использовать для таймера. и я также хотел бы указать вам, что NSTimer нельзя использовать повторно. следовательно, если вы хотите выполнить эту операцию после того, как вы аннулировали ее, вам нужно заново создать таймер и добавить его в цикл выполнения.

// 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];
    }
}
person nsuinteger    schedule 30.05.2014