视图不会立即显示
Posted
技术标签:
【中文标题】视图不会立即显示【英文标题】:View is not displayed immediately 【发布时间】:2014-01-01 12:22:22 【问题描述】:我想要达到的目标:
使用以下行为创建带有一些自定义图标、标签等的处理屏幕。
在窗口上添加视图,在删除之前不允许用户触摸应用程序中的任何内容。 (如处理/加载屏幕)
当显示此视图时,所有其他操作(如添加子视图、执行 segue 等)应该正常工作,但在我的加载视图下方。
希望方法 showProcessingScreen 在任何线程上工作(无论线程切换代码等应该在各自的显示/隐藏方法中)。
应在调用相应方法后立即显示/删除。代码:
-(void) showProcessingScreen
dispatch_async(dispatch_get_main_queue(),
^
UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle:nil];
processingScreen = [mystoryboard instantiateViewControllerWithIdentifier:@"loadingViewController"];
UIWindow* mainWindow = [[UIApplication sharedApplication] keyWindow];
[mainWindow addSubview: processingScreen.view];
[mainWindow bringSubviewToFront:processingScreen.view];
);
-(void) hideProcessingScreen
dispatch_async(dispatch_get_main_queue(),
^
[processingScreen.view removeFromSuperview];
);
问题:
我希望上面的代码能够立即显示/隐藏加载屏幕。
- (IBAction)proceedBtnPressed:(id)sender
[[GUIUtilities sharedObj] showProcessingScreen];
//Some other code here
当我像上面那样调用 showProcessingScreen 时,处理屏幕大约需要 2-3 秒才能显示。 但是当我删除它下面的其他代码(//其他一些代码)时,它会立即显示屏幕。
我尝试过的:
-
将代码放在 showProcessingScreen 中的其他方法中,并使用 performSelectorOnMainThread 在主线程上调用。
在后台调用 showProcessingScreen 并使用 performSelector 在主线程上执行显示代码。
这行得通
//代码
-(IBAction)proceedBtnPressed:(id)sender
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
^
[[GUIUtilities sharedObj] showProcessingScreen];
//Some other code here
);
但我不想要 showProcessingScreen 之外的任何线程切换机制。
这是几乎在每个应用程序中都使用的常见屏幕。我在 xib 中使用了类似的代码,在我以前的应用程序中没有使用故事板等的自定义视图, 我知道这与线程有关,我在这里做错了什么?实现这一目标的最佳做法是什么? 任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:问题在于,当您调度时,您将加载视图的创建放在运行循环的末尾。无论您的“其他代码”是什么,都会阻塞主线程几秒钟。
如果您将此“其他代码”移至其他线程,这将解决您的问题。 (这个解决方案很理想。)
你也可以只有条件地切换到主线程,如果你从主线程调用加载视图,这将解决问题:
-(void) showProcessingScreen
if (![NSThread isMainThread])
[self performSelectorOnMainThread:@selector(showProcessingScreen) withObject:nil waitUntilDone:FALSE];
return;
UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle:nil];
processingScreen = [mystoryboard instantiateViewControllerWithIdentifier:@"loadingViewController"];
UIWindow* mainWindow = [[UIApplication sharedApplication] keyWindow];
[mainWindow addSubview: processingScreen.view];
[mainWindow bringSubviewToFront:processingScreen.view];
【讨论】:
是的,这就是我之前写的方式。但它不起作用:(它曾经用于非基于故事板的视图。 你明白为什么它不工作了吗?看看我所说的将“其他代码”移动到后台线程。【参考方案2】:无需添加拦截触摸事件的覆盖视图,您只需调用
– beginIgnoringInteractionEvents
– endIgnoringInteractionEvents
【讨论】:
不是我所问问题的解决方案,我需要自定义叠加视图,因为我想显示一些带有微调器、标签等的自定义视图 可以,但您不需要“拦截触摸事件”。【参考方案3】:你可以试试这个:
- (void)doSomeOtherCode
//Some other code here
- (IBAction) showProcessingScreenAndDoSomeOtherCode:(id)sender
[[GUIUtilities sharedObj] showProcessingScreen];
[self performSelector:@selector(doSomeOtherCode) withObject:nil afterDelay:0.0];
- (IBAction)proceedBtnPressed:(id)sender
[self showProcessingScreenAndDoSomeOtherCode:self];
它会起作用的。关于您的评论:
但我不想要 showProcessingScreen 之外的任何线程切换机制。
上述解决方案不会导致showProcessingScreen
之外的任何线程切换。 performSelector
只会在事件循环队列中添加一个条目。
编辑:
如果你使用块,同样的结果可以通过:
dispatch_async(dispatch_get_main_queue(),
^
[[GUIUtilities sharedObj] showProcessingScreen];
dispatch_async(dispatch_get_main_queue(), ^
//Some other code here
);
);
或:
dispatch_async(dispatch_get_main_queue(),
^
[[GUIUtilities sharedObj] showProcessingScreen];
);
dispatch_async(dispatch_get_main_queue(), ^
//Some other code here
);
由于主队列是串行队列,showProcessingScreen
和“这里的一些其他代码”将被串行执行。
【讨论】:
感谢您的回答。是的,它有效,但我会从代码的不同部分调用 showProcessingScreen。然后我需要多次编写 doSomeOtherCode 之类的方法,并且在某些情况下 doSomeOtherCode 将需要一些参数。所以不适合我的情况。 查看我编辑的答案以解决您的第一个问题;至于第二个,那些参数是什么?如果您有参数,那么您的proceedBtnPressed
无法传递它们,那么您将如何处理呢?
不适合从嵌套代码调用 showProcessingScreen。而且我需要在我调用它的每个类中编写类似于 doSomeOtherCode 的方法。我想要一些机制,它可以让我在不接触其他代码的情况下展示它
我不确定我是否完全理解“嵌套代码”的含义,我认为它的意思是“块”。在这种情况下,请参阅我的编辑。以上是关于视图不会立即显示的主要内容,如果未能解决你的问题,请参考以下文章