是否可以在执行同步调用或其他操作时更新UI中的内容?

时间:2013-12-09 14:30:13

标签: ios objective-c nsnotificationcenter uikeyboard

在我的项目中的几个点,我需要执行一些同步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的东西会帮助我。

实际上,它看起来似乎没有任何支持在同步操作期间更改屏幕,这实在令人失望。我现在没有想法。

3 个答案:

答案 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