2014-04-11 65 views
1

我有這樣的代碼等待裝載任務,呈現出activityIndi​​cator視圖什麼是UI動畫和主要runloop之間的關係

if (isLoading) { 
    self.tipView = [[BBTipsView alloc] initWithMessage:@"loading..." showLoading:YES parentView:self.view autoClose:NO]; 
    self.tipView.needsMask = YES; 
    [self.tipView show]; 
    while (isLoading) { 
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
    } 
    [self.tipView close]; 
} 

加載視圖將動畫,直到isLoading成爲false.here是我的問題: 在主線程中運行runloop會阻塞主線程,直到發生源事件或定時器觸發爲止。但是爲什麼在主循環沒有返回時加載視圖保持動畫?

-----通過bupo ----

編輯我發現,當定時觸發runloop將不會返回。這將有意義的動畫刷新ui由CADisplayLink定時器火災。

Note that from the perspective of NSRunloop, NSTimer objects are not "input"—they are a special type, and one of the things that means is that they do not cause the run loop to return when they fire. 
+0

現代動畫很少有做的RunLoop。它們依賴稱爲顯示鏈接的定時器基元,後者可以在後臺線程上運行,以確保與顯示器相連的刷新率,而不是CPU。 – CodaFi

+0

你的意思是UI刷新沒有在主線程上運行? –

+0

你得到的顯示回調只是主線程。計時器是在後臺運行的。 – CodaFi

回答

0

runMode:beforeDate:運行,直到給定日期或NSRunLoop方法,直到找到一個單一的事件處理 - 在此之後,調用返回。你在主運行循環中調用它([NSRunLook currentRunLoop])。因此,即使你認爲你阻止了主要的運行循環,你也沒有 - 你正在爲事件提供服務。因此,動畫計時器可以起作用,即使您可能認爲您在「阻止」主運行循環。

要確認這一點,請將電話註釋掉runMode:beforeDate:,您應該看到UI凍結,直到操作完成。

編輯:請參閱CodaFi對您的問題的評論。如果您注意撥打runMode:beforeDate:,出於興趣,實際上會發生什麼?

原來的答覆:

不建議用於啓動和停止UI動畫的代碼這種風格。 除非必須,否則不要亂跑循環。並且有一個檢查從其他地方更改布爾標誌的緊密循環往往是代碼異味,這意味着有更好的方法。

相反,這樣做異步,沒有坐在主線程:

// on main thread 
    self.tipView = [[BBTipsView alloc] initWithMessage:@"loading..." showLoading:YES parentView:self.view autoClose:NO]; 
    self.tipView.needsMask = YES; 
    [self.tipView show]; 
} // end of the method 

- (void)loadingHasFinished { 
    // assuming this method called on main thread 
    [self.tipView close]; 
} 

很明顯,你就必須確保loadingHasFinished稱爲爲宜。

如果loadingHasFinished被稱爲後臺線程而非主線程,你會想是這樣的:

- (void)loadingHasFinished { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self.tipView close]; 
    }); 
}; 
+0

是的,我知道還有更好的辦法。但在這種情況下,我只想知道如果通過主runloop ui動畫刷新ui? –

+0

我已經更新了我的答案。 – occulus

+0

嗨,occulus,你的答案有幫助。非常感謝。 –

相關問題