在我的项目中的几个点,我需要执行一些同步Web服务调用或从CoreData读取。执行这些操作可能需要几秒钟,因此我创建了一个LoadingView
类,它是UIView
的子类,具有简单消息和UIActivityIndicatorView
。对于普通UIButton
,我[myLoadingView setHidden:NO]
事件只有Touch Down
,[myLoadingView setHidden:YES]
事件只有Touch Up Inside
。这一切都正是我想要的。
问题是我无法通过键盘上的Return
键找到解决方法。据我所知,当用户触摸Return
键(UITextFieldDelegate
protocol
textFieldShouldReturn:
)时,只有一种方法被调用,我需要两种方法来能够得到我的[myLoadingView setHidden:NO]
- >使用[myLoadingView setHidden:YES]
技术,因为Objective-C直到方法结束才更新屏幕,而不是像其他语言一样不断更新屏幕。
如果用户触摸Return
键,执行某些操作,并在操作完成后隐藏加载屏幕,如何让我的加载屏幕显示?
修改:
我尝试过使用NSNotificationCenter
,但我似乎遇到了同样的问题。例如,如果我有UIButton
Touch Up Inside
方法:
- (void) btnClick:(id) sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"Show Loading" object:nil];
// Do stuff that takes a long time here
[[NSNotificationCenter defaultCenter] postNotificationName:@"Hide Loading" object:nil];
}
我的LoadingView.m
中的位置:
- (id) init
{
self = [super init];
if (self)
{
// Do normal init stuff here
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showLoading) name:@"Show Loading" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hideLoading) name:@"Hide Loading" object:nil];
}
return self;
}
- (void) showLoading
{
// Do stuff to set up the loading screen
[self setHidden:NO];
}
- (void) hideLoading
{
[self setHidden:YES];
}
设置如下,当我点击按钮时,我从未看到加载屏幕。 当我发布通知时,它会立即执行并更改屏幕吗?如果确实如此,我必须做错事,可能在我的// Do stuff
部分。如果没有,我认为NSNotificationCenter
不会帮助我任何=(。
编辑2:
我设置了一个快速测试项目,我确认通知不会立即更新屏幕。我在上一次编辑中发布的btnClick
代码与单纯执行
- (void) btnClick:(id) sender
{
[loadingView setHidden:NO];
// Do stuff that takes a long time here
[loadingView setHidden:YES];
}
这样就确认没有任何依赖NSNotificationCenter
的东西会帮助我。
实际上,它看起来似乎没有任何支持在同步操作期间更改屏幕,这实在令人失望。我现在没有想法。
答案 0 :(得分:2)
您需要从您呼叫的任何进程进行回调,以告知您已完成。当回调触发时,您可以隐藏加载屏幕。
答案 1 :(得分:1)
您还可以使用didEndOnExit
文本字段事件,当您按下返回键时会被触发。
您可以在此方法中开始显示活动指示器视图,并且在加载完成时,您可以使用一些回调(在Web服务的情况下 - NSURLConnectionDataDelegate
协议方法:connectionDidFinishLoading)来隐藏指示器视图。
答案 2 :(得分:0)
我最终使用Grand Central Dispatch来处理这个问题。
最简单的方法- (void) doStuff
{
// Show wait on start
[myLoadingView setHidden:NO];
dispatch_queue_t queue = dispatch_queue_create("com.myDomain.myApp",null);
dispatch_async(queue, ^{
// Code to execute
{
//... Do my time consuming stuff here ...
// For testing purposes, I'm using
int i = 0;
while (i < 1000000000)
{
i++;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
// Hide Wait Screen on End
// ... also need to do any other UI stuff here ...
[myLoadingView setHidden:YES];
});
});
}
不幸的是,我的实际time consuming stuff
中有一些GUI更改(例如显示警报,预先形成segues,更改标签等)。我没有重写整个事情以尝试将所有GUI内容都拉出来,而是发现将它全部嵌套在另一个dispatch_async
中,我仍然可以在操作执行时显示等待屏幕,以及所有其他GUI time consuming stuff
中完成的内容会在完成后更新(等待屏幕消失后)。
- (void) doStuff
{
// Show wait on start
[myLoadingView setHidden:NO];
dispatch_queue_t queue = dispatch_queue_create("com.myDomain.myApp",null);
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
// Double nesting the dispatches seems to allow me to do UI changes as part of 'Code to execute' below.
// If I do not double nest like this, GUI behavior in "time consuming stuff" will be erratic
dispatch_queue_t queue2 = dispatch_queue_create("com.myDomain.myApp",null);
dispatch_async(queue2, ^{
dispatch_async(dispatch_get_main_queue(), ^{
// Code to execute
{
//... Do my time consuming stuff here - GUI changes will appear when all the code has finished running ...
// For testing purposes, I'm using
int i = 0;
while (i < 1000000000)
{
i++;
}
}
// Hide Wait Screen on End
[myLoadingView setHidden:YES];
});
});
});
});
}
请注意,如果doStuff
需要返回一个值,您可能需要将其更改为使用“完成块”detailed in the accepted answer here。