2012-12-11 178 views
0

我有一個方法,我添加到我創建的GCD隊列(所以它是一個串行隊列),然後運行它的異步。從那段代碼中,我派遣到主隊列,當派發到主隊列的代碼塊完成時,我將一個BOOL標誌設置爲YES,這樣我在代碼中進一步下來可以檢查這個條件是否爲YES那麼我可以繼續下一個方法。下面是短代碼:等待的條件繼續

dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0); 

dispatch_async(queue, ^{ 

     Singleton *s = [Singleton sharedInstance]; 

     dispatch_sync(dispatch_get_main_queue(), ^{ 
      [s processWithCompletionBlock:^{ 

       // Process is complete 
       processComplete = YES; 
      }]; 
     }); 
}); 

while (!processComplete) { 

     NSLog(@"Waiting"); 
} 

NSLog(@"Ready for next step"); 

然而,這是不行的,因爲dispatch_sync從來都不是能夠在主隊列運行代碼。這是因爲我在主隊列上運行一個while循環(使其處於繁忙狀態)?

但是,如果我改變而循環的實現這樣:

while (!processComplete) { 

     NSLog(@"Waiting") 
     NSDate *date = [NSDate distantFuture]; 
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date]; 
} 

它工作無故障。這是這種情況下可接受的解決方案嗎?我可以做任何其他首選的方式嗎? NSRunLoop做什麼樣的魔術?我需要更好地理解這一點。

回答

2

主線程的NSRunLoop作業的一部分是運行在主線程上排隊的任何塊。通過在while循環中旋轉,可以防止runloop的進展,所以排隊的塊永遠不會運行,除非您自己明確地讓循環運行。

Runloops是可可的一個可愛的部分,documentation是相當不錯的,所以我建議閱讀它。

通常,我會避免手動調用runloop。如果您有多個手動調用運行在另一個之上,則會浪費內存並使事情變得非常迅速。

但是,這樣做有更好的方法。將你的方法分解成一個-process和一個-didProcess方法。使用-process方法啓動異步操作,並在完成時從完成塊中調用-didProcess。如果您需要將變量從一種方法傳遞給另一種方法,則可以將它們作爲參數傳遞給-didProcess方法。

如:

dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0); 

dispatch_async(queue, ^{ 
     Singleton *s = [Singleton sharedInstance]; 

     dispatch_sync(dispatch_get_main_queue(), ^{ 
      [s processWithCompletionBlock:^{ 
       [self didProcess]; 
      }]; 
     }); 
}); 

您還可以考慮讓你的單身自己的調度隊列,使其負責處理dispatch_async的東西,因爲它會在所有這些討厭的嵌入式模塊保存,如果你總是異步使用它。

如:

[[Singleton sharedInstance] processAyncWithCompletionBlock:^{ 
    NSLog(@"Ready for next step..."); 
    [self didProcess]; 
}]; 
+0

所以,如果我不是要從主隊列(主線程)進行回調,我可以使用派遣信號量(http://stackoverflow.com/q/4326350/294661)或甚至使用我的解決方案(無需手動調用runloop)? –

+0

是的......儘管如果你在一個串行隊列中,那麼提交到該隊列的任何塊將不會運行,直到塊結束。爲什麼你需要根本阻止線程?你需要從調用方法返回一個值嗎? –

+0

我需要等待一個過程才能完成,然後才能繼續。不,我不需要返回一個值。 –

1

做你發佈的內容很可能會凍結用戶界面。不要凍結所有內容,請在完成塊中調用您的「下一步」代碼。

例子:

dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0); 
dispatch_queue_t main = dispatch_get_main_queue(); 

dispatch_async(queue, ^{ 

     Singleton *s = [Singleton sharedInstance]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      [s processWithCompletionBlock:^{ 
       // Next step code 
      }]; 
     }); 
}); 
+1

具體來說,派遣塊做的工作,並在此塊(當工作完成後)內派遣一個塊回主隊列更新您的UI。這將盡可能有效地使用多線程來保持您的應用程序響應(無沙灘球)。 –

+0

是的,確切地說。 :) –

+0

添加了一個未經測試的示例。 –

-2

不要去創造這樣的等待塊中值的循環,在塊中的變量是隻讀的,而不是從塊內調用您的完成代碼。

dispatch_async(queue, ^{ 
    Singleton *s = [Singelton sharedInstance]; 
    [s processWithCompletionBlock:^{ 
     //process is complete 
     dispatch_sync(dispatch_get_main_queue(), ^{ 
      //do something on main queue.... 
      NSLog(@"Ready for next step"); 
     }); 
    }]; 
}); 
NSLog(@"waiting"); 
+1

爲什麼不呢?如果塊中的FYI變量聲明爲「__block」 –

+0

...,則它們也是可寫的,如果它們在塊中本地聲明的話。 –