2016-11-24 5 views
-1

以下のサンプルコードがあります。iOS 10 while(YES)never break

- (void)method1 
{ 
    breakFlag = NO; 
    [self performSelectorInBackground:@selector(method2) withObject:nil]; 

    while (YES) { 
     if (breakFlag) { 
      break; 
     } 
    } 
    NSLog(@"End method1"); 
} 

- (void)method2 
{ 
    for (int i = 0; i < 10000; i++) { 
     NSLog(@"value of i; %d", i); 
    } 

    breakFlag = YES; 
    NSLog(@"End method2"); 
} 

私は

[self performSelectorInBackground:@selector(method1) withObject:nil]; 

breakFlagが可変のインスタンスであるとviewDidAppearから法1と呼ばれます。

なぜメソッド1は中断されないのですか?代わりの

+0

'method2'の' NSLog'文はすべて表示されていますか? – rmaddy

+2

これはある種のテストコードですか?あなたは確かにこのような実際のコードを望んでいないでしょう。 – rmaddy

+0

デバッガで実行しましたか? – clemens

答えて

0

CとObjective-Cコンパイラは、スレッドの本当に意識していません。彼らは、言語標準によれば、あなたの-method1のようなコードを完全に調べることができ、ループのコードのなかにはbreakFlagが変わっていないことを確認して、ループからチェックを引き上げて最適化します。それはそれはbreakFlagを変更しないことを知ることができないので、それは-performSelectorInBackground:...を呼び出した後breakFlagをチェックする必要がない

- (void)method1 
{ 
    breakFlag = NO; 
    [self performSelectorInBackground:@selector(method2) withObject:nil]; 

    if (!breakFlag) { 
     while (YES) { 
     } 
    } 
    NSLog(@"End method1"); 
} 

:それはそれはにあなたの方法を最適化し、あります。しかし、ループ内でチェックする必要はありません。

breakFlagvolatile修飾子で宣言すると、この最適化が妨げられます。これはコンパイラに何かが "自発的に"(分析できるものの外で)breakFlagをいつでも変更できることを伝えます。

しかし、これは決してコードを書く正しい方法ではありません。あなたが達成しようとしていることを言うことを拒否したので、それを達成するためのより良い方法について助言するのは難しいです。一般的には、セマフォやmutexなどの適切なスレッド同期プリミティブを使用して、スレッドが相互作用するようにすることをお勧めします。

0

[self performSelectorInBackground:@selector(method2) withObject:nil]; 

試してみてください。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    [self method2]; 
});