setKeepAliveTimeout e BackgroundTasks

Estou com uma grande dor de cabeça com o tópico. Estou trabalhando em um aplicativo que precisa pesquisar regularmente um servidor da web, a fim de verificar novos dados. Com base nas informações retornadas, desejo enviar uma notificação local ao usuário.

Eu sei que essa abordagem é um pouco diferente da descrita pela Apple, na qual um servidor remoto faz o trabalho, enviando uma notificação remota, com base no APNS. No entanto, existem muitas razões pelas quais não posso levar essa abordagem em consideração. Um por todos, é o mecanismo de autenticação do usuário. O servidor remoto, por motivos de segurança, não pode levar em consideração as credenciais do usuário. Tudo o que posso fazer é mover o núcleo de login e busca, para o cliente (iPhone).

Notei que a Apple oferece uma oportunidade para os aplicativos serem ativados e manterem aberta uma conexão Socket (ou seja, um aplicativo VoIP).

Então, comecei a investigar dessa maneira. Adicionadas as informações necessárias no plist, sou capaz de "acordar" meu aplicativo, usando algo parecido com isso no meu appDelegate:

[[UIApplication sharedApplication] setKeepAliveTimeout:1200 handler:^{ 
    NSLog(@"startingKeepAliveTimeout");
    [self contentViewLog:@"startingKeepAliveTimeout"];
    MyPushOperation *op = [[MyPushOperation alloc] initWithNotificationFlag:0 andDataSource:nil];
    [queue addOperation:op];
    [op release];
}];

O NSOperation, em seguida, inicia uma tarefa em segundo plano usando o seguinte código de bloco:

#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];
        });
    }
}

O código acima parece funcionar (algumas vezes), mas muitos outros travam meu aplicativo, com as seguintes informações de log:

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

Para quem pergunta, sim. Também tentei a abordagem Async NSURLConnection. Não importa. Ele trava da mesma forma, mesmo se eu usar uma abordagem assíncrona com o manipulador de tempo limite e didFinishLoading: WithError.

Estou preso. Todas as dicas são muito apreciadas.

questionAnswers(4)

yourAnswerToTheQuestion