Да, каждый раз, когда вызывается метод setKeepAliveTimeout, я создаю новую конечную фоновую задачу (которая, кажется, запускается в течение 10 минут).
я большая головная боль с темой. Я работаю над приложением, которое должно регулярно опрашивать веб-сервер, чтобы проверять наличие новых данных. На основании возвращенной информации я хочу отправить локальное уведомление пользователю.
Я знаю, что этот подход немного отличается от того, который изображает Apple, в котором удаленный сервер выполняет работу, выдвигая удаленное уведомление, основанное на APNS. Однако есть много причин, по которым я не могу принять этот подход во внимание. Одним из всех является механизм аутентификации пользователя. Удаленный сервер по соображениям безопасности не может учитывать учетные данные пользователя. Все, что я могу сделать - это перенести ядро входа и загрузки на клиент (iPhone).
Я заметил, что Apple дает возможность приложениям активироваться и держать открытым соединение Socket (т.е. приложение VoIP).
Итак, я начал исследовать таким образом. Добавил необходимую информацию в plist, я могу "разбудить" мое приложение, используя что-то вроде этого в моем appDelegate:
[[UIApplication sharedApplication] setKeepAliveTimeout:1200 handler:^{
NSLog(@"startingKeepAliveTimeout");
[self contentViewLog:@"startingKeepAliveTimeout"];
MyPushOperation *op = [[MyPushOperation alloc] initWithNotificationFlag:0 andDataSource:nil];
[queue addOperation:op];
[op release];
}];
Затем NSOperation запускает фоновую задачу, используя следующий код блока:
#pragma mark SyncRequests
-(void) main {
NSLog(@"startSyncRequest");
[self contentViewLog:@"startSyncRequest"];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"exipiration handler triggered");
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
[self cancel];
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableURLRequest *anURLRequest;
NSURLResponse *outResponse;
NSError *exitError;
NSString *username;
NSString *password;
NSLog(@"FirstLogin");
anURLRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:webserverLogin, username, password]]];
[anURLRequest setHTTPMethod:@"GET"];
[anURLRequest setTimeoutInterval:120.00];
[anURLRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
exitError = nil;
NSData *tmpData = [NSURLConnection sendSynchronousRequest:anURLRequest returningResponse:&outResponse error:&exitError];
[anURLRequest setTimeoutInterval:120.00];
if(exitError != nil) { //somethings goes wrong
NSLog(@"somethings goes wrong");
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
[self cancel];
return;
}
//do some stuff with NSData and prompt the user with a UILocalNotification
NSLog(@"AlltasksCompleted");
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
[self cancel];
});
}
}
Вышеприведенный код, кажется, работает (иногда), но во многих других он приводит к сбою моего приложения со следующей информацией журнала:
Exception Type: 00000020
Exception Codes: 0x8badf00d
Highlighted Thread: 3
Application Specific Information:
DemoBackApp[5977] has active assertions beyond permitted time:
{(
<SBProcessAssertion: 0xa9da0b0> identifier: UIKitBackgroundCompletionTask process: DemoBackApp[5977] permittedBackgroundDuration: 600.000000 reason: finishTask owner pid:5977 preventSuspend preventIdleSleep
)}
Elapsed total CPU time (seconds): 0.010 (user 0.010, system 0.000), 100% CPU
Elapsed application CPU time (seconds): 0.000, 0% CPU
Для тех, кто спрашивает, да. Я тоже попробовал подход Async NSURLConnection. Независимо от того. Сбой тот же, даже если я использую асинхронный подход с обработчиком тайм-аута и didFinishLoading: WithError.
Я застрял. Любые намеки высоко ценятся.