我有以下代码:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Loading Content For the First Time..."
message:@"\n"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(139.5, 75.5); // .5 so it doesn't blur
[alertView addSubview:spinner];
[spinner startAnimating];
[alertView show];
for (TCMLevelRemote *level in [obj objectForKey:@"levels"]){
[[TCMExhibitFeedStore sharedStore] createLevel:level];
}
[[TCMExhibitFeedStore sharedStore] loadAllLevels];
[[TCMExhibitFeedStore sharedStore] setAllLevels:[[TCMExhibitFeedStore sharedStore] storedLevels]];
[alertView dismissWithClickedButtonIndex:0 animated:YES];
for循环需要一段时间才能执行,因为它会在应用首次运行时下载一些信息。因此,我希望此通知显示,以便用户不会坐在无响应的屏幕上等待。问题是在for循环结束之前,alertview不会显示。然后它马上就消失了。我需要改变什么?
答案 0 :(得分:11)
在 .h 类中声明您的alert-view
对象,以便在 .m 类中的任何位置使用。
将您的for循环代码放在performSelectorInBackground
中,以便在Backgroud中运行循环,这样您就可以不等待ForLoop的完成了。
[self performSelectorInBackground: @selector(LoadForLoop) withObject: nil];
-(void)LoadForLoop
{
for (TCMLevelRemote *level in [obj objectForKey:@"levels"]){
[[TCMExhibitFeedStore sharedStore] createLevel:level];
}
[[TCMExhibitFeedStore sharedStore] loadAllLevels];
[[TCMExhibitFeedStore sharedStore] setAllLevels:[[TCMExhibitFeedStore sharedStore] storedLevels]];
[alertView dismissWithClickedButtonIndex:0 animated:YES];
}
其他解决方案
您也可以按照代码使用Grand Central Dispatch (GCD),如下所示: -
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Loading Content For the First Time..."
message:@"\n"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(139.5, 75.5); // .5 so it doesn't blur
[alertView addSubview:spinner];
[spinner startAnimating];
[alertView show];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (TCMLevelRemote *level in [obj objectForKey:@"levels"]){
[[TCMExhibitFeedStore sharedStore] createLevel:level];
}
[[TCMExhibitFeedStore sharedStore] loadAllLevels];
[[TCMExhibitFeedStore sharedStore] setAllLevels:[[TCMExhibitFeedStore sharedStore] storedLevels]];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner StopAnimating];
[alertView dismissWithClickedButtonIndex:0 animated:YES];
});
});
答案 1 :(得分:1)
我认为您正在寻找的是在警报视图向用户显示活动指示器时创建“级别”。
现在,您在与UI代码相同的线程上运行for
循环。您的代码将按顺序,一行一行地运行。在iOS和Mac OS上,必须为线程的run loop提供空间以允许渲染和计时事件,在本例中为动画。通过阻止运行循环直到for
循环结束,您的UIAlertView
将没有时间在循环之后设置动画,然后您的dismissWithClickedButtonIndex:animated:
调用会立即隐藏它。
您要做的是将处理转移到后台,使用Grand Central Dispatch:
// Perform all of your UI on the main thread:
// ... set up your alert views, etc
// Then shift your logic to a background thread:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// This block is executed on a background thread, so will not block the UI:
for (TCMLevelRemote *level in [obj objectForKey:@"levels"]){
[[TCMExhibitFeedStore sharedStore] createLevel:level];
}
[[TCMExhibitFeedStore sharedStore] loadAllLevels];
[[TCMExhibitFeedStore sharedStore] setAllLevels:[[TCMExhibitFeedStore sharedStore] storedLevels]];
// Finally, now that your background process is complete, you can update the interface accordingly by dismissing the alert view:
dispatch_async(dispatch_get_main_queue(), ^{
[alertView dismissWithClickedButtonIndex:0 animated:YES];
});
});
在处理后台线程时,务必注意必须在主线程上执行UI事件 。
我喜欢将我的任务打包到NSOperation子类中,这有助于将UI与模型逻辑分开,也可以为我处理GCD。我会把它作为锻炼给你。
关于您选择UI的附注:警报视图并非用于通知用户某些进程。它们用于警告用户发生单个事件 。我建议使用像MBProgressHUD这样的东西,特别是因为它内置了对doSomethingInBackgroundWithProgressCallback:completionCallback:
的GCD方法的支持。
答案 2 :(得分:0)
不显示警报视图,因为您的循环阻止了主线程,这是必须绘制警报视图的线程。
在您最初拥有代码的地方,请写下:
// Your original code that creates and sets up the alertView
UIAlertView* alertView = ...
// Add this snippet
NSTimeInterval delay = 0.1; // arbitrary small delay
[self performSelector:@selector(delayedLoop:) withObject:alertView afterDelay:delay];
// Show the alert. Because the delayedLoop: method is invoked
// "a little bit later", the main thread now should be able to
// display your alert view
[alertView show];
将此方法添加到您的班级:
- (void) delayedLoop:(UIAlertView*)alertView
{
// Add your code that runs the loop and dismisses the alert view
}
此解决方案有点“hackish”,但由于您的循环仍在主线程上下文中运行,因此您不会遇到任何线程问题。如果您愿意在辅助线程中执行循环,那么您应该看看Nithin Gohel的答案。