2010-11-16 2 views
0

Я пишу очень простое приложение OSX. В этом приложении есть основной поток, который обновляет некоторые вещи, затем вычисляет некоторую статистику и печатает их в textView.выполнение останавливается на [textView insertText:] без исключения!

При разработке я использовал тот же полученный IBAction для выполнения этого цикла. Я получил все это, а затем переключился на NSThread, чтобы пользовательский интерфейс не блокировался при вычислении.

Как только я это сделал, приложение запустило очень мало циклов (около 7-8), а затем все приложение зависает без каких-либо исключений. Отлаживая, я заметил, что он зависает при попытке распечатать статистику в текстовом элементе, и я совершенно не знаю, как это решить. Он работает, если не внутри потока ... Любой может помочь? Код ниже. Заранее спасибо :)

-(IBAction) Evolve:(id)sender{ 
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
[NSThread detachNewThreadSelector:@selector(Evolve) toTarget:self withObject:nil]; 
[pool drain]; 
} 

И это весь цикл

-(void) Evolve{ 

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    srandom(time(NULL)); 

    //Tag 0: Minimo, Tag 1: Massimo 
    int tagMinMax = [MinMax selectedTag]; 

    //Tag 0: Rimpiazza sempre, Tag 1: Rimpiazza solo se migliori 
    int tagRimpiazzo = [[Rimpiazzo selectedItem] tag]; 

    int PopNum = [tf_popNum intValue]; 
    int maxGen = [tf_maxGen intValue]; 
    int target = [tf_targetVal intValue]; 
    int chromosomeLength = [tf_chromosomeLength intValue]; 

    Environment *env = [[Environment alloc] init]; 

    NSMutableArray *pop = [[NSMutableArray alloc] init]; 
    for (int i = 0; i < PopNum; i++) { 
     [pop addObject:[[Individual alloc] initWithRandomGenesWithChromosomeLength:chromosomeLength]]; 
    } 

    [env setPopulation:pop]; 
    [pop release]; 

    BOOL earlyBestFound = NO; 
    Individual *earlyBest = nil; 
    int i=0; 
    float best, avg; 
    while (i<maxGen && !earlyBestFound) { 
     NSLog(@"while"); 
     NSArray *parents = [env selectParents]; 
     NSLog(@"parents selected"); 
     NSMutableArray *offspring = [[NSMutableArray alloc] init]; 
     for (int i = 0; i < [parents count]; i+=2) { 
      if (i+1<[parents count]) { 
       NSLog(@"beginning SEX"); 
       Individual *parent1 = [parents objectAtIndex:i]; 
       Individual *parent2 = [parents objectAtIndex:i+1]; 

       NSArray *children = [parent1 kCrossOverWithOtherIndividual:1 individual:parent2]; 

       Individual *child1 = [children objectAtIndex:0]; 
       Individual *child2 = [children objectAtIndex:1]; 

       NSLog(@"children born"); 

       if (tagRimpiazzo!=0) { 
        if (([child1 fitness] > [parent1 fitness] && tagMinMax == 0)||([child1 fitness] < [parent1 fitness] && tagMinMax == 1)) { 
         child1 = parent1; 
        } 
        if (([child2 fitness] > [parent2 fitness] && tagMinMax == 0)||([child2 fitness] < [parent2 fitness] && tagMinMax == 1)) { 
         child2 = parent2; 
        } 
       } 

       NSLog(@"Replacement happened"); 

       [offspring addObject:child1]; 
       [offspring addObject:child2]; 
      } 
     } 
     NSLog(@"Calculating statistics"); 
     avg = 0; 
     for(Individual *X in offspring){ 

      if (([X fitness] > best && tagMinMax == 1)||([X fitness] < best && tagMinMax == 0)) { 
       best = [X fitness]; 
      } 

      avg += [X fitness]; 

      if ([X fitness]==target) { 
       earlyBestFound = YES; 
       earlyBest = X; 
      } 
     } 
     avg = avg/(float)PopNum; 

     [env setPopulation:offspring]; 

     NSLog(@"Releasing some memory"); 

     [offspring release]; 

     NSLog(@"Printing statistics"); 
     NSString *toPrint = [NSString stringWithFormat:@"Fine generazione: %d avg: %.2f best: %.2f \r\n", i,avg,best]; 
     [textView insertText:toPrint]; 

     i++; 
    } 

    NSLog(@"Fine"); 

    NSString *toPrint = [NSString stringWithFormat:@"Fine! best: %.2f - avg: %.2f \r\n", i,avg,best]; 
    [textView insertText:toPrint]; 

    [env release]; 

    [pool drain]; 
} 

P.S. Извините, если английский не идеален, я итальянский :)

ответ

2

Ваше приложение разбивается, потому что вы получаете доступ к textView из фоновой темы. Объекты пользовательского интерфейса могут быть доступны только из основного потока.

Для решения проблемы вам нужно перенаправить текстовые обновления в основной поток пользовательского интерфейса. Вы можете сделать это, используя метод -performSelectorOnMainThread:. Например:

[textView performSelectorOnMainThread:@selector(insertText:) 
          withObject:toPrint 
         waitUntilDone:YES]; 
+0

Большое спасибо, что сработало! Я не знал этого. Могу ли я спросить, почему я могу получить доступ к объектам пользовательского интерфейса из основного потока? – XelharK

+0

Это потому, что структура пользовательского интерфейса не является потокобезопасной. Как правило, они не связаны с сложностью обеспечения безопасности потоков. – willcodejavaforfood

Смежные вопросы