2010-06-02 66 views
2

我敢肯定,這非常簡單,我只是缺少一些明顯的東西。我有一個應用程序需要從Web服務下載數據以顯示在UITableView中,如果操作需要超過X秒的時間才能完成,我想顯示一個UIAlertView。所以這是我有什麼(簡化爲簡潔起見):NSTimer作爲超時機制

MyViewController.h

@interface MyViewController : UIViewController 
     <UITableViewDelegate, UITableViewDataSource> { 
    NSTimer *timer; 
} 

@property (nonatomic, retain) NSTimer *timer; 

MyViewController.m

@implementation MyViewController 

@synthesize timer; 

- (void)viewDidLoad { 
    timer = [NSTimer scheduledTimerWithTimeInterval:20 
      target:self 
     selector:@selector(initializationTimedOut:) 
     userInfo:nil 
     repeats:NO]; 

    [self doSomethingThatTakesALongTime]; 
    [timer invalidate]; 
} 

- (void)doSomethingThatTakesALongTime { 
    sleep(30); // for testing only 
    // web service calls etc. go here 
} 

- (void)initializationTimedOut:(NSTimer *)theTimer { 
    // show the alert view 
} 

我的問題是,我期待[self doSomethingThatTakesALongTime]調用阻止,而定時器不斷計數,我在想,如果它完成計時器完成倒計時之前,它將返回線程控制到viewDidLoad其中[timer invalidate]將繼續取消定時器。很顯然,我對定時器/線程如何工作的理解在這裏存在缺陷,因爲代碼編寫的方式,定時器永遠不會關閉。但是,如果我刪除了[timer invalidate],它會。

回答

3

我認爲在調度計時器和在同一個線程上執行阻塞調用時會出現問題。在阻塞呼叫完成之前,運行循環不能觸發定時器。

我建議你分離一個線程來執行長操作。長操作完成後,回調主線程以使定時器無效。

注意:在計劃的同一線程上使計時器失效很重要。

- (void)viewDidLoad { 
    timer = [NSTimer scheduledTimerWithTimeInterval:20 
      target:self 
     selector:@selector(initializationTimedOut:) 
     userInfo:nil 
     repeats:NO]; 

    [NSThread detachNewThreadSelector:@selector(doSomethingThatTakesALongTime:) toTarget:self withObject:nil]; 
} 

- (void)doSomethingThatTakesALongTime:(id)arg { 
    sleep(30); // for testing only 
    // web service calls etc. go here 
    [self performSelectorOnMainThread:@selector(invalidate) withObject:nil waitUntilDone:NO]; 
} 

- (void)invalidate { 
    [timer invalidate]; 
} 

- (void)initializationTimedOut:(NSTimer *)theTimer { 
    // show the alert view 
} 
+0

這工作得很好。我唯一需要做的就是在doSomethingThatTakesAlongTime中初始化一個NSAutoreleasePool。謝謝! – alexantd 2010-06-02 23:38:53

+0

備註:當使計時器無效時,在使計時器無效並將計時器設置爲零之後,通常都會檢查計時器是否爲零。 – Groot 2013-04-17 11:40:42

0

您是否嘗試過使用[NSThread sleepforTimeInterval:30];

0

sleep()發生在主線程和相關的運行循環從來沒有調用選擇定時器的機會。

如果您在-doSomething中做了不妨礙線程的實際工作,例如,非阻塞的Web服務調用,它會按預期工作。但是,阻止呼叫必須在不同的線程中完成,因此主運行循環不會被阻止。