Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 等待结果而不停止UI_Iphone_Ios_Ipad - Fatal编程技术网

Iphone 等待结果而不停止UI

Iphone 等待结果而不停止UI,iphone,ios,ipad,Iphone,Ios,Ipad,我有一个iPad应用程序,我想这样做 -(IBAction) clicked { image=download(@"http://....."); // this is on the main thread } 下载函数将调用一大堆非阻塞函数从internet下载文件,但下载本身在图像下载之前不应返回 当程序在上面的image=download(…)行等待下载时,我希望UI能够正常工作,例如能够滚动UITableView,单击其他按钮等 所以我在下载函数中使用了RunLoop -(vo

我有一个iPad应用程序,我想这样做

-(IBAction) clicked {
    image=download(@"http://....."); // this is on the main thread
}
下载函数将调用一大堆非阻塞函数从internet下载文件,但下载本身在图像下载之前不应返回

当程序在上面的image=download(…)行等待下载时,我希望UI能够正常工作,例如能够滚动UITableView,单击其他按钮等

所以我在下载函数中使用了RunLoop

-(void) download:(NSString *)url 
{
    BOOL stillDownloading=TRUE;
    while(stillDownloading) {
        stillDownloading=downloadAFwBytes(...);
        CFRunLoopRunInMode(kCFRunLoopCommonModes, 0, YES);
    }
}
我认为CFRunLoopRunInMode函数将不断在主UI线程中发送UI消息、触摸、滚动,这样UI将继续工作,并且在下载完成之前不会冻结,但由于某些原因,它只在短时间内工作,最终UI冻结

你知道为什么,或者如何修复吗


下载功能在程序中的任何地方都被调用,希望它等待下载,所以我现在不能将其更改为非阻塞。

您的问题涉及到一些架构问题,但要在后台正确下载图像并将其加载到UIImageView或以任何其他方式使用它,我建议您查看并通读他们下载资源的示例代码。

您可以请求在后台下载图像,然后在您的方法中尽快返回静态图像吗

这样,主线程返回速度很快,并且根据您的架构,您的后台线程可以在获得图像后更新它


我认为我们需要更多关于您的代码的详细信息(您的下载方法是无效的,那么下载的数据是如何使用的?)才能真正提供帮助。

您的问题的直接答案是,不,这不是
CFRunLoopRunInMode
所做的。实际上,您要做的是让当前运行循环“yield”,以便在加载操作继续的同时继续执行。这不是iOS和run循环的工作方式。下载功能会阻止它所打开的线程,直到下载完成,因此解决问题的唯一方法是更改实现,以便在后台线程上进行下载,并在下载完成时通知关心的对象。这里有一个相对较小的变化,可以让你走上正确的轨道。这个总体主题(并发性、管理后台任务)是一个更大的讨论,有不同的考虑/权衡。我会切入正题,希望能让你走上正轨

  • 定义一对
    NSNotification
    ,您的下载方法可以将其发布给感兴趣的对象以供观察:

    // in the .h file of the class performing the download
    extern NSString * const MyClassLoadingDidStartNotification;
    extern NSString * const MyClassLoadingDidFinishNotification;
    
    // in the .m file of the class performing the download
    NSString * const MyClassLoadingDidStartNotification = @"MyClassLoadingDidStart";
    NSString * const MyClassLoadingDidFinishNotification = @"MyClassLoadingDidFinish";
    
  • 在下载例程中,在后台进行下载并发布相应的通知:

    -(void) download:(NSString *)url 
    {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [[NSNotificationCenter defaultCenter] postNotificationName:MyClassLoadingDidStartNotification object:self];
            BOOL stillDownloading=TRUE;
            while(stillDownloading) {
                stillDownloading=downloadAFwBytes(...);
            }
            [[NSNotificationCenter defaultCenter] postNotificationName:MyClassLoadingDidFinishNotification object:self];
        });
    }
    
  • 在任何启动下载的对象中,观察并处理通知

    // in any class that initiates a download
    - (void)init...
    {
        self = [super init...];
        if (self) {
            // other initialization
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didStartLoading:) name:MyClassLoadingDidStartNotification object:nil];
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFinishLoading:) name:MyClassLoadingDidFinishNotification object:nil];
        }
        return self;
    }
    
    - (void)dealloc
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:MyClassLoadingDidStartNotification object:nil];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:MyClassLoadingDidFinishNotification object:nil];
    }
    
    - (void)didStartLoading:(NSNotification *)notification
    {
        // update UI to show loading status (make sure you do UI changes on main thread)
        // optionally check notification.object to ensure it's the loader class instance you care about
    }
    
    - (void)didFinishLoading:(NSNotification *)notification
    {
        // update UI to show loading status (make sure you do UI changes on main thread)
        // optionally check notification.object to ensure it's the loader class instance you care about
    }
    

  • 请记住,这是一个非常基本的起点。当您了解更多信息并决定需要什么时,您肯定会定制它。例如,您可能希望添加错误处理、限制并发加载操作、提供其他加载状态等。

    与其他三位同事告诉您同样的事情,我将告诉您忘记您自己的运行循环模型,只需使用异步下载功能(假设您是通过网络下载)。您甚至不必构建线程,只需启动异步下载,下载完成后他们就会告诉您。如果您没有时间编写正确的代码,您什么时候有时间修复代码?

    不确定这是否已解决,但您不能使用

    [self.operationQueue addOperationWithBlock:^{
        [self MethodName];
    }];
    
    当您希望在UI中发生类似表更新的事情时,请将其放入方法代码中:

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
     ////perform something here ////
    }];
    

    希望这能有所帮助。

    我知道这不是一个好办法,但有没有办法让它像这样工作,我稍后会更改它,但现在没有时间了@当然,时间是有的,你现在就应该改变它,其实没那么难……以上是对真实事物的简化,这要复杂得多。要改变它需要大量的输入,我想我可以在上面的循环中添加一些东西,以便在仍然处于while循环的情况下处理UI消息?这可能吗?问题是这只是一个函数,这个方法在整个程序中被用来请求不同的东西,而不仅仅是图像。调用方希望在函数返回时返回项,但这会停止进程中的UI。所以我加入了RunLoop来尝试解决这个问题,但它在挂起之前只工作了一段时间。我可以在while循环中放入任何东西来解决问题吗?不知道。但我在文档中读到了这一点:“您不能为mode参数指定kCFRunLoopCommonModes常量。运行循环始终在特定模式下运行。您仅在配置运行循环观察者时指定公共模式,并且仅在您希望该观察者在多个模式下运行的情况下指定公共模式。”谢谢,您知道我可以使用哪种模式,以便runloop处理UI消息,从而使UI不会冻结吗?这不是RunLoop的主要目的吗?就像@Erator一样,我认为您遇到了一个需要尽快解决的架构问题。如果你必须快速交付一些东西,你不能在下载过程中显示一个计时器来阻止任何新的UI输入,但给用户一些关于发生了什么的反馈吗?我担心使用RunLoop会很棘手,而且如果所有东西都在主线程上运行,那么无论如何都会有性能问题。很不幸,如果boss希望主线程不阻塞,我建议您努力使这个东西异步