¿Cómo descargar un archivo y guardarlo en el directorio de documentos con AfNetWorking?

StackOverflow https://stackoverflow.com/questions/8372661

  •  27-10-2019
  •  | 
  •  

Pregunta

Estoy usando la biblioteca AfNetworking. No puedo entender cómo descargar un archivo y guardarlo en el directorio de documentos.

¿Fue útil?

Solución

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];

Otros consejos

Voy a rebotar 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 objeto Manager con AFJSONRESPONSESERIALIZA DE AFJSONESSERA Predeterminado, y realiza una restricción de tipos de contenido. Mira esto

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

Por lo tanto, necesitamos crear un serializador de respuesta de Ninguno y usar AFHTTPRequestOperationManager como normal.

Aquí está el AfnonerSponseSerializer

@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 obtener el archivo completo sin ninguna serialización

Página de documentación tiene 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! Código de trabajo con iOS 7+ (probado con AfNetworking 2.5.1)

De Avenida docs. Guarde en el archivo cargado en 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];
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];

// gerente.esponseSerializer.acceptableContentTypes = [nsset setWithObject: @"Application/Octet-stream"]; puede variar según lo que espere

Si, es mejor usar AFNetworking 2.0 camino AFHTTPRequestOperationManager. Con el antiguo camino, mi archivo se descargó, pero por alguna razón no se actualizó en el sistema de archivos.

Apuntan a Swilliam's respuesta, para mostrar el progreso de descarga, en AFNetworking 2.0 De manera similar, solo configure el bloque de progreso de descarga después de configurar la transmisión 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 una cadena 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 la secuencia de salida también es necesaria para evitar que la aplicación colgue (y eventualmente se bloquea por falta de memoria).

operation.outputStream = [NSOutputStream outputStreamToFileAtPath:dest
                                                          append:NO];
[operation.outputStream open];
[operation start];
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top