Актуализиране на текста на етикета (динамично) при изпълнение на друг метод

Аз съм разработчик на 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", Box 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
Селекторът Perform ще публикува съобщение до обекта, подобно на [self method]. Има различен претоварен селектор за изпълнение, който помага да се постигнат много неща, освен извикването на метод. За напр. Метод може да бъде извикан след забавяне. В нашия случай, тъй като актуализираме потребителския интерфейс, това трябва да бъде публикувано в основната нишка. Така че използвах performSelectorOnMainThread, за да накарам селектора да се изпълни в основната нишка. - person Naveen Prasad R; 30.05.2014

не е много добра идея да изпълнявате безкраен цикъл на основната нишка (uithread). Вместо това мога ли да ви предложа да използвате таймер или събитие за изпращане? по-долу има код, който можете да използвате за таймер. и също така бих ви посочил, че 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