2011-08-19 82 views
0

因此,當我點擊我的mapView中的標註附件時,幾秒鐘內沒有任何反應,因爲它正在發出url請求並解析它,所以我想顯示活動指示器,以便用戶不認爲它已凍結。下面的代碼:iPhone活動指示燈被延遲?

- (void)mapView:(MKMapView *)mv annotationView:(MKAnnotationView *)pin calloutAccessoryControlTapped:(UIControl *)control { 
    // start activity indicator 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 
    NSLog(@"tapped"); 

    ArtPiece *artPiece = (ArtPiece *)pin.annotation; 

    //when annotation is tapped switches page to the art description page 
    artDescription *artD = [[artDescription alloc] initWithNibName:@"artDescription" bundle:nil]; 
    artD.modalTransitionStyle = UIModalTransitionStyleCoverVertical; 
    artD.startingLocation = mapView.userLocation.location.coordinate; 
    artD.selectedArtPiece = artPiece; 
    NSLog(@"0"); 
    [self presentModalViewController:artD animated:YES]; 
    NSLog(@"1"); 

    [artD loadArt:artPiece]; 
    NSLog(@"2"); 
    // stop activity indicator 
    //[UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 

    [artD release]; 
} 

奇怪(我反正,也許我失去了一些東西明顯,因爲我很沒有經驗),活動指示燈不顯示,直到方法完成後,和模態視圖開始動畫到視圖中。我把NSLogs放進去看看需要花費什麼時間。我在「0」和「1」之間停頓了2秒,在「1」和「2」之間停了兩秒鐘。然後指標終於顯示出來,所以我確信它由於某種原因一直等到該方法結束。任何想法爲什麼?

回答

3

的變化到UI,顯示活動的指標,不生效直到控制權返回到應用程序的main run loop。直到方法結束並且堆棧解除後纔會發生這種情況。你需要展示活動的指標,然後甩了你正在等待到後臺線程活動:

[self performSelectorInBackground:@selector(doThingINeedToWaitFor:) 
         withObject:anObject]; 

(注意蘋果recommendsmove away from using threads explicitly; performSelectorInBackground:withObject:是讓流失的最簡單的方法,一些代碼的主要更復雜的選項可用於其他情況請參閱Concurrency Programming Guide

重要的問題是UI更新仍然需要在主線程上處理,因此在該方法中,工作完成後,您需要回電停止活動指示燈:

- (void) doThingINeedToWaitFor: (id)anObject { 
    // Creating an autorelease pool should be the first thing 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    // Do your work... 
    // ... 
    // Update the UI back on the main thread 
    [self performSelectorOnMainThread:@selector(allDoneWaiting:) 
          withObject:nil 
         waitUntilDone:YES]; 
    // Clear out the pool as the final action on the thread 
    [pool drain]; 
} 

在您的回調方法中,您會再次隱藏活動指示符並執行必要的任何其他後處理。

+0

所以allDoneWaiting會成爲另一種方法:[UIApplication sharedApplication] .networkActivityIndi​​catorVisible = YES; ? – Ryan

+0

它可能會根據您的需要做其他事情,但基本上,是的。任何接觸GUI的代碼都需要在主線程上運行。 –

+0

好的謝謝你的幫助,還有一個問題:它崩潰並抱怨一個autorelease池,我需要圍繞doThingINeedToWaitFor方法做些什麼嗎? – Ryan

3

您不能在同一功能中啓動和停止活動指示器。

見我提供了這個問題的答案:How show activity-indicator when press button for upload next view or webview?

編輯爲清楚:

- (void) someFunction 
{ 
    [activityIndicator startAnimation]; 

    // do computations .... 

    [activityIndicator stopAnimation]; 
} 

上面的代碼將無法工作,因爲你不給UI時間更新時,您包括activityIndi​​cator在你當前運行的函數中。所以我和其他許多人做的是把它分解成一個單獨的線程像這樣:

- (void) yourMainFunction { 
    activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 

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

    //Your computations 

    [activityIndicator stopAnimating]; 

} 

- (void) threadStartAnimating { 
    [activityIndicator startAnimating]; 
} 
+1

UI變化需要在主線程中發生。活動指示器需要在'yourMainFunction'中開始動畫,一個線程需要被「分離」(GCD,NSOperation,NSThread,POSIX)來執行計算,然後回調主線程以停止動畫。 – Joe

0

東西正在放緩您的微調。我會建議在後臺使用一個線程來完成你的繁重工作。試試這個:

-(void)myMethod{ 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 
    [NSThread detachNewThreadSelector:@selector(startWorkingThread) toTarget:self withObject:nil]; 
} 

-(void)startWorkingThread{ 
    //Heavy lifting 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
} 

我假設你有評論的:

[UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 

出於測試目的...