2016-11-24 48 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"); 
} 

我叫方法1從viewDidAppear

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

breakFlag是可變的實例。

爲什麼在method1中永遠不會被破壞?

+0

你看到'method2'的所有'NSLog'語句嗎? – rmaddy

+2

這是某種測試代碼嗎?你當然不希望這樣的真實代碼。 – rmaddy

+0

您是否在調試器中運行過它? – clemens

回答

0

C和Objective-C編譯器是沒有真正意識到線程的。根據語言標準,它們完全有權檢查代碼,如-method1,並且看到循環代碼中沒有任何內容會更改breakFlag,並通過提取循環檢查來優化它。也就是說,它優化了你的方法爲:

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

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

它需要調用-performSelectorInBackground:...後檢查breakFlag,因爲它無法知道這不會改變breakFlag。但它不需要在循環中檢查它。

如果您要聲明breakFlagvolatile限定符,那將阻止此優化。這告訴編譯器,任何事情都可以「自發地」(除了它可以分析的東西)隨時修改breakFlag

但是,這幾乎從來都不是編寫代碼的正確方法。既然你拒絕透露你想要完成的任務,很難爲你提供更好的實現方法。一般的建議是建議你使用適當的線程同步原語,比如信號量,互斥等,讓線程交互。

0

相反的:

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

嘗試:

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