¿Cómo download un file y savelo en el directory de documentos con AFNetworking?

Estoy usando la biblioteca AFNetworking. No puedo entender cómo download un file y guárdalo en el directory de documentos.

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"..."]]; AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"filename"]; operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"Successfully downloaded file to %@", path); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@", error); }]; [operation start]; 

Voy a rebotar en la respuesta de @mattt y publicar una versión para AFNetworking 2.0 usando AFHTTPRequestOperationManager .

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"filename"]; AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; AFHTTPRequestOperation *op = [manager GET:@"http://example.com/file/to/download" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"successful download to %@", path); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@", error); }]; op.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO]; 

Estoy hablando de AFNetworking 2.0

[AFHTTPRequestOperationManager manager] crea el object de administrador con AFJSONResponseSerializer pnetworkingeterminado y realiza la restricción de types de contenido. Mira esto

 - (BOOL)validateResponse:(NSHTTPURLResponse *)response data:(NSData *)data error:(NSError * __autoreleasing *)error 

Por lo tanto, necesitamos crear un serializador de ninguna respuesta y utilizar AFHTTPRequestOperationManager manera normal.

Aquí está el AFNoneResponseSerializer

 @interface AFNoneResponseSerializer : AFHTTPResponseSerializer + (instancetype)serializer; @end @implementation AFNoneResponseSerializer #pragma mark - Initialization + (instancetype)serializer { return [[self alloc] init]; } - (instancetype)init { self = [super init]; return self; } #pragma mark - AFURLResponseSerializer - (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error { return data; } @end 

Uso

 self.manager = [AFHTTPRequestOperationManager manager]; self.manager.responseSerializer = [AFNoneResponseSerializer serializer]; [self.manager GET:@"https://sites.google.com/site/iphonesdktutorials/xml/Books.xml" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) { if (success) { success(responseObject); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (failure) { failure(error); } }]; 

para que podamos get todo el file sin serialization

La página de documentation tiene un ejemplo con la sección 'Creación de una tarea de descarga':

 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; NSURL *URL = [NSURL URLWithString:@"http://example.com/download.zip"]; NSURLRequest *request = [NSURLRequest requestWithURL:URL]; NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil]; return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]]; } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { NSLog(@"File downloaded to: %@", filePath); }]; [downloadTask resume]; 

¡NÓTESE BIEN! El trabajo de código con iOS 7+ (probado con AFNetworking 2.5.1)

 AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.responseSerializer = [AFCompoundResponseSerializer serializer]; manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"application/octet-stream"]; AFHTTPRequestOperation *operation = [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { if (responseObject) { // your code here } else { // your code here } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { }]; [operation start]; 

// manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject: @ "application / octet-stream"]; puede variar según lo que esperas

De los documentos de AFNetworking . Guardar en file cargado a sus documentos. AFNetworking 3.0

 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; NSURL *URL = [NSURL URLWithString:@"http://example.com/download.zip"]; NSURLRequest *request = [NSURLRequest requestWithURL:URL]; NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil]; return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]]; } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { NSLog(@"File downloaded to: %@", filePath); }]; [downloadTask resume]; 

Sí, es mejor usar AFNetworking 2.0 con AFHTTPRequestOperationManager . Con la vieja manera mi file se descargó pero por alguna razón no se actualizó en el sistema de files.

Anexando a la respuesta de swilliam , para mostrar el progreso de la descarga, en AFNetworking 2.0 lo hace de manera similar: solo establezca el bloque de progreso de descarga después de configurar la secuencia de salida.

 __weak SettingsTableViewController *weakSelf = self; operation.outputStream = [NSOutputStream outputStreamToFileAtPath:newFilePath append:NO]; [operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToRead) { float progress = totalBytesWritten / (float)totalBytesExpectedToRead; NSString *progressMessage = [NSString stringWithFormat:@"%@ \n %.2f %% \n %@ / %@", @"Downloading ...", progress * 100, [weakSelf fileSizeStringWithSize:totalBytesWritten], [weakSelf fileSizeStringWithSize:totalBytesExpectedToRead]]; [SVProgressHUD showProgress:progress status:progressMessage]; }]; 

Este es mi método para crear cadenas de bytes:

 - (NSString *)fileSizeStringWithSize:(long long)size { NSString *sizeString; CGFloat f; if (size < 1024) { sizeString = [NSString stringWithFormat:@"%d %@", (int)size, @"bytes"]; } else if ((size >= 1024)&&(size < (1024*1024))) { f = size / 1024.0f; sizeString = [NSString stringWithFormat:@"%.0f %@", f, @"Kb"]; } else if (size >= (1024*1024)) { f = size / (1024.0f*1024.0f); sizeString = [NSString stringWithFormat:@"%.0f %@", f, @"Mb"]; } return sizeString; } 

Además de las respuestas anteriores, con AFNetworking 2.5.0 e iOS7 / 8, he descubierto que el paso adicional de abrir el flujo de salida también es necesario para evitar que la aplicación cuelgue (y eventualmente se cuelgue debido a la falta de memory).

 operation.outputStream = [NSOutputStream outputStreamToFileAtPath:dest append:NO]; [operation.outputStream open]; [operation start];