ios nsurlsession nsurlsessionuploadtask

ios - Cómo obtener datos de respuesta del servidor en NSURLSession sin bloque de finalización



nsurlsessionuploadtask (1)

Estoy usando NSURLSession para subir imágenes de fondo. Y, de acuerdo con la imagen cargada, mi servidor me responde y, en consecuencia, cambio en mi aplicación. Pero no puedo obtener la respuesta de mi servidor cuando mi aplicación carga la imagen en segundo plano porque no hay un bloque de finalización.

¿Hay forma de obtener respuesta sin usar el bloque de finalización en NSURLUploadTask ?

Aquí está mi código:

self.uploadTask = [self.session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSString *returnString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"returnString : %@",returnString); NSLog(@"error : %@",error); }]; [self.uploadTask resume];

Pero tengo este error ..

Aplicación de terminación debido a la excepción no detectada ''NSGenericException'', motivo: ''Los bloques de controlador de finalización no se admiten en sesiones de fondo. Utilice un delegado en su lugar.

Pero si no puedo usar el controlador de finalización, ¿cómo debo obtener la respuesta del servidor? Dice usar delegado pero no puedo encontrar ningún método de delegado que me dé respuesta del servidor.


Un par de pensamientos:

Primero, cree una instancia de su sesión con un delegate , porque las sesiones de fondo deben tener un delegado:

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kSessionIdentifier]; self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];

En segundo lugar, NSURLSessionUploadTask una instancia de NSURLSessionUploadTask sin un controlador de finalización, ya que las tareas agregadas a una sesión en segundo plano no pueden usar bloques de finalización. También tenga en cuenta que estoy usando una URL de archivo en lugar de un NSData :

NSURLSessionTask *task = [self.session uploadTaskWithRequest:request fromFile:fileURL]; [task resume];

Tercero, implementar los métodos de delegado relevantes. Como mínimo, eso podría parecer:

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { NSMutableData *responseData = self.responsesData[@(dataTask.taskIdentifier)]; if (!responseData) { responseData = [NSMutableData dataWithData:data]; self.responsesData[@(dataTask.taskIdentifier)] = responseData; } else { [responseData appendData:data]; } } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (error) { NSLog(@"%@ failed: %@", task.originalRequest.URL, error); } NSMutableData *responseData = self.responsesData[@(task.taskIdentifier)]; if (responseData) { // my response is JSON; I don''t know what yours is, though this handles both NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil]; if (response) { NSLog(@"response = %@", response); } else { NSLog(@"responseData = %@", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]); } [self.responsesData removeObjectForKey:@(task.taskIdentifier)]; } else { NSLog(@"responseData is nil"); } }

Tenga en cuenta que lo anterior se está aprovechando de un NSMutableDictionary llamado NSMutableDictionary (porque, para mi disgusto, estos métodos de delegado de "tarea" se realizan en el nivel de "sesión").

Por último, desea asegurarse de definir una propiedad para almacenar la handleEventsForBackgroundURLSession completionHandler proporcionada por handleEventsForBackgroundURLSession :

@property (nonatomic, copy) void (^backgroundSessionCompletionHandler)(void);

Y, obviamente, handleEventsForBackgroundURLSession delegado de su aplicación responda a handleEventsForBackgroundURLSession , guardando el completionHandler , que se utilizará a continuación en el método URLSessionDidFinishEventsForBackgroundURLSession .

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler { // This instantiates the `NSURLSession` and saves the completionHandler. // I happen to be doing this in my session manager, but you can do this any // way you want. [SessionManager sharedManager].backgroundSessionCompletionHandler = completionHandler; }

Y luego, asegúrese de que su NSURLSessionDelegate llame a este controlador en el hilo principal cuando NSURLSessionDelegate la sesión en segundo plano:

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { if (self.backgroundSessionCompletionHandler) { dispatch_async(dispatch_get_main_queue(), ^{ self.backgroundSessionCompletionHandler(); self.backgroundSessionCompletionHandler = nil; }); } }

Esto solo se llama si algunas de las cargas terminaron en segundo plano.

Hay algunas partes móviles, como puede ver, pero eso es básicamente lo que implica.