iPhone活动指示灯被延迟?

问题描述:

因此,当我点击我的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”之间停了两秒钟。然后指标终于显示出来,所以我确信它由于某种原因一直等到该方法结束。任何想法为什么?

的变化到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

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

见我提供了这个问题的答案: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

东西正在放缓您的微调。我会建议在后台使用一个线程来完成你的繁重工作。试试这个:

-(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; 

出于测试目的...