gpt4 book ai didi

iOS:NSURLConnection 回调严重延迟或根本未触发

转载 作者:行者123 更新时间:2023-11-29 12:36:40 24 4
gpt4 key购买 nike

我有一个 VoIP iOS 应用程序使用长轮询机制来维护其服务连接和接收事件(调用)。这意味着,NSURLConnection 会等待几分钟,但会在事件发生后立即返回。由于 VoIP 标志,即使应用程序处于后台模式,也可以设置保持事件处理程序并接收更新。

然而,这在大多数情况下都有效但不可靠。有时,即使在请求超时(达到 NSURLRequesttimeoutInterval)之后,NSURLConnection 回调也会严重延迟或根本不会触发。

日志中的示例以阐明:

  • 应用以后台模式运行(由系统在启动时启动)
  • NSURLConnection #1(长轮询)启动并在 1 分钟后返回一些新数据
  • NSURLConnection #2(长轮询)启动并在 15 分钟(服务器端最大值)后返回,没有任何新数据
  • (...)
  • NSURLConnection #99(长轮询)已启动但不返回 - 即使 timeoutInterval 过期(16 分钟)
  • 不时调用保持事件处理程序,但没有任何反应。 backgroundTimeRemaining 属性获得了不切实际的高值(1797693134862315708145274237317043567980705675258449965989174768031572607800285387605895586327668 7817154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932894407586850845513339423045832 36903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 而不是最大值 180.0)。
  • 1 小时后,用户打开应用。该应用能够执行各种 NSURLRequest 并接收响应
  • 几秒钟后,用户关闭应用
  • 再过 10 分钟后,NSURLConnection #99 回调 didFailWithError 被触发并出现超时错误 (-1001)。此请求的执行时间超过 1 小时,即使 timeoutInterval 被限制在 16 分钟内,还有其他几个请求较晚启动但较早完成。

在我看来,这似乎是 iOS 的一种非常奇怪的行为。为什么 iOS 应该为应用程序提供后台执行时间并调用保持事件处理程序,但不能及时正确触发 NSURLConnection 回调?

保持事件处理程序:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

[[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{

NSLog(@"########### Started Keep-Alive Handler ###########");

[self startBackgroundHandler:YES timeout:30];

NSLog(@"########### Completed Keep-Alive Handler ###########");

}];

[self startBackgroundHandler:NO timeout:60];

}

-(void)startBackgroundHandler:(BOOL)force timeout:(int)timeout {
UIApplicationState currentAppState = [[UIApplication sharedApplication] applicationState];
BOOL appIsBackground = currentAppState == UIApplicationStateBackground;
if(appIsBackground || force) {

int localThreadId = ++_currentBackgroundThreadId;

__block UIBackgroundTaskIdentifier bgTask;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
NSLog(@"Cleaning up [Background Thread %d] ...", localThreadId);
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];

NSLog(@"startBackgroundHandler with [Background Thread %d] appIsBackground=%d force=%d", localThreadId, appIsBackground, force);

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

if(_currentBackgroundThreadId == localThreadId) {
NSLog(@"[Background Thread %d] Background time left: %0.1f", localThreadId, [UIApplication
sharedApplication].backgroundTimeRemaining);
sleep(timeout);
}

NSLog(@"[Background Thread %d] Will exit...", localThreadId);
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
} else {
NSLog(@"Ignored startBackgroundHandler - appIsBackground=%d force=%d", appIsBackground, force);
}
}

所有 NSURLConnections 都有一个 runloop - 它们启动如下:

NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:mrequest delegate:self startImmediately:NO];
if(connection) {
[connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[connection start];

} else {
// error handling...
}

附言:在较早版本的应用程序中,使用data fetch 后台模式而不是voip,并且从未遇到过此类问题。

最佳答案

当你在后台时,iOS 似乎不愿意在主线程上给你 CPU 时间——即使你有 VoIP 标志。因此,您应该在单独的线程中安排您的请求,并使用 CFRunLoopRun() 使其在后台运行。此外,您必须在运行循环中使用 runMode:beforeDate: 以适当的模式触发执行。

但真正的问题是,如果请求超时太频繁,iOS 将停止提供 CPU 时间——您确实需要接收任何东西才能获得 CPU 时间。因此,让WebServer及时回复很重要。

关于iOS:NSURLConnection 回调严重延迟或根本未触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26141460/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com