iOS UIScrollView使用NSRunLoopCommonModes卡住并且没有响应

在我的iPhone应用程序中,我使用第三方库(libPusher)进行WebSockets网络,这个库导致我的应用程序中的每个UIScrollView组件都无响应.这包括UIScrollViews和UITableView.

会发生的情况是,如果用户用他的手指滚动其中一个UIScrollView组件并且碰巧在网络操作正在进行的同时用手指触摸和滑动视图,那么这会导致完全无响应的UIScrollView停止接受触摸事件(即使手指抬起,它也认为它一直处于拖动模式)并且没有适当减速.唯一的出路是销毁UIScrollView并重新创建一个新的.

我联系了图书馆的开发者,但不幸的是到目前为止还没有收到回复.

从我读到的,这是一个常见的问题,当在一个不合适的模式运行一个运行循环,如NSDefaultRunLoopMode,但是这个库似乎正在做正确的事情,它在NSRunLoopCommonModes运行其运行循环,所以我不清楚什么是正确的解决方案.

我尝试使用不同的模式(尝试NSDefaultRunLoopMode),但行为是相同的.

我正在使用iOS 5,它在模拟器和设备上的行为相同.

让我粘贴我认为在lib中存在问题的代码,希望这足以让你帮助我找到解决方案.

在NSOperation的子类中,我们有:

- (void)start 
{
  NSAssert(URLRequest, @"Cannot start URLRequestOperation without a NSURLRequest.");

  [self setExecuting:YES];

  URLConnection = [[NSURLConnection alloc] initWithRequest:URLRequest delegate:self startImmediately:NO];

  if (URLConnection == nil) {
    [self setFinished:YES]; 
  }

  // Common modes instead of default so it won't stall uiscrollview scrolling
  [URLConnection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
  [URLConnection start];

  do {
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
  } while (!_isFinished);
}

此操作在主线程上运行,如[[NSOperationQueue mainQueue] addOperation:authOperation] ;. (也许这是问题所在,但我尝试在另一个线程中运行它崩溃所以库需要更多的工作才能使后台线程安全,所以我无法证明这是解决方案……)

到目前为止我试过了

>将运行循环模式更改为NSDefaultRunLoopMode – 没有帮助.
>在我创建的新操作队列中运行操作(例如,不在主线程上)但是库在崩溃时似乎没有为此做好准备.

我还是觉得我在黑暗中拍摄……帮助:)

谢谢!

最佳答案 它变得没有响应,因为它在主线程上执行了一个while循环.这是一个糟糕的设计模式.

既然你在iOS5上,为什么不使用NSURLConnection的sendAsynchronousRequest:queue:completionHandler 😕

如果你需要兼容iOS4.x,我会删除运行循环的东西,看看this blog post.

基本上,我会做这样的事情:

- (void)start
{
    if (![NSThread isMainThread]) {
        return [self performSelectorOnMainThread:@selector(start) 
                                      withObject:nil
                                   waitUntilDone:NO];
    }

    [self willChangeValueForKey:@"isExecuting"];
    isExecuting = YES;
    [self didChangeValueForKey:@"isExecuting"];

    NSURLConnection *aConnection = [[NSURLConnection alloc] initWithRequest:request 
                                                                   delegate:self];

    self.connection = aConnection;
    [aConnection release];

    if (connection == nil) {
        // finish up here
    }
}
点赞