异步NSURLConnection打破了计时器

时间:2015-01-30 20:47:05

标签: ios objective-c asynchronous nsurlconnection

我设置了一个类来处理我的Web API调用。这是使用NSMutableURLRequestNSRLlConnection完成的。我最初使用connectionWithRequest: delegate:并且在大多数情况下运行良好,除非我依赖于此请求是真正的异步,而不仅仅是在主运行循环中部分执行。

要做到这一点,我想我会使用非常方便的sendAsynchronousRequest: queue: completionHandler:,并且在我的所有单元测试中,我认为这很有效。它以异步方式执行,我的信号量等待并正确发出信号,这很棒。

直到我尝试在我的实际应用中重新使用这个新的Web服务类修改版本。我的应用程序的一部分播放视频,并使用重复NSTimer根据视频的当前播放时间更新部分屏幕。由于某些未知原因,只要我执行了这些新的异步NSURLConnection中的至少一个,视频播放和计时器都不再有效。

以下是我初始化连接的方法:

[NSURLConnection sendAsynchronousRequest:requestMessage
                                   queue:[[NSOperationQueue alloc] init]
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
                       {
                           if ( data.length > 0 && connectionError == nil )
                           {
                               _webServiceData = [data mutableCopy];
                               [self performSelector:@selector(connectionDidFinishLoading:) withObject:nil];
                           }
                           else if ( connectionError != nil )
                           {
                               _webServiceData = [data mutableCopy];
                               [self performSelector:@selector(webServiceDidFinishExecutingWithError:) withObject:connectionError];
                           }
                       }];

以下是我初始化重复计时器的方法:

playbackTimeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkPlaybackTime) userInfo:nil repeats:YES];

我完全不知道为什么异步NSURLConnection导致我的应用程序的各个方面与停止运行完全无关。

修改

为了澄清我有ViewControllerA执行网络请求以检索一些数据。成功检索到该数据后,ViewControllerA会自动转换为ViewControllerBViewControllerB viewWillAppear是我设置电影播放器​​和计时器的地方。

1 个答案:

答案 0 :(得分:0)

  1. 将来,请勿使用信号量进行测试等待。使用专为测试异步进程而设计的新XCTestExpectation

    与传统的信号量技巧不同,使用测试期望并不会阻塞主线程,因此如果您有完成块或需要主线程的委托,则可以结合测试期望来执行此操作。 / p>

  2. 您显然正在做一些不起作用的事情,因为您在后台队列中运行此功能。典型问题包括

    • 如果您尝试从后台线程运行该计时器,那将无法正常工作,除非您使用其中一个标准计时器变通办法(在主runloop上安排它,将计时器的创建重新分配回来)到主线程,使用调度计时器等。)。

      之前已经非常详细地描述了这些替代方案,结果发现你从viewWillAppear启动了计时器,所以这都是学术性的。

    • 任何UI更新(包括执行segues,重新加载表等)。

    • 在同步从后台线程更新的类属性时应该小心(这些也可能最好被分派到主线程)。

    无论如何,您可以通过告诉sendAsynchronousRequest在主队列上运行其完成块来解决这个问题:

    [NSURLConnection sendAsynchronousRequest:requestMessage
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
        ...
    }]; 
    

    然后,完成块将在后台队列上运行,一切都可能没问题。或者您可以手动将完成处理程序的调用重新分配回主队列。

    但请确保在主线程上运行任何UI更新(包括以编程方式执行segue)(通过在主线程上运行整个完成块,或者手动将相关调用分派给主线程)。 / p>