ios 如何使用 AFNetworking 下载文件并将其保存到文档目录?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8372661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:44:08  来源:igfitidea点击:

How to download a file and save it to the documents directory with AFNetworking?

iosiphoneafnetworking

提问by iamsmug

I am using the AFNetworking library. I can't figure out how to download a file and save it to the documents directory.

我正在使用 AFNetworking 库。我不知道如何下载文件并将其保存到文档目录。

回答by mattt

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

回答by swilliams

I'm gonna bounce off @mattt's answer and post a version for AFNetworking 2.0 using AFHTTPRequestOperationManager.

我要从@mattt 的回答中反弹并使用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];

回答by onmyway133

I'm talking about AFNetworking 2.0

我说的是AFNetworking 2.0

[AFHTTPRequestOperationManager manager]creates manager object with default AFJSONResponseSerializer, and it performs content types restriction. Take a look at this

[AFHTTPRequestOperationManager manager]使用默认的 AFJSONResponseSerializer 创建管理器对象,并执行内容类型限制。看看这个

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

So we need to create a none response serializer and use AFHTTPRequestOperationManageras normal.

所以我们需要创建一个无响应序列化器并AFHTTPRequestOperationManager正常使用。

Here is the AFNoneResponseSerializer

这是 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

Usage

用法

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

so that we can get the whole file without any serialization

这样我们就可以在没有任何序列化的情况下获取整个文件

回答by Maxim Kholyavkin

Documentation pagehas example with section 'Creating a Download Task':

文档页面的示例包含“创建下载任务”部分:

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

NB! Code work with iOS 7+ (tested with AFNetworking 2.5.1)

注意!代码适用于 iOS 7+(使用 AFNetworking 2.5.1 测试)

回答by Mr.Fingers

From AFNetworkingdocs. Save to loaded file to your documents. AFNetworking 3.0

来自AFNetworking文档。将加载的文件保存到您的文档。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];

回答by Satyam Raikar

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"]; can vary depending on what you expect

// manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject: @"application/octet-stream"]; 可以根据您的期望而有所不同

回答by Denis Kutlubaev

Yes, it is better to use AFNetworking 2.0way with AFHTTPRequestOperationManager. With old way my file did download but for some reason didn't update in file system.

是的,最好将AFNetworking 2.0way 与AFHTTPRequestOperationManager. 使用旧方式,我的文件确实下载了,但由于某种原因没有在文件系统中更新。

Appending to swilliam'sanswer, to show download progress, in AFNetworking 2.0you do similarly - just set download progress block after setting output stream.

附加到swilliam 的答案,显示下载进度,在AFNetworking 2.0你做类似的 - 只需在设置输出流后设置下载进度块。

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

This is my method to create bytes string:

这是我创建字节字符串的方法:

- (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;
}

回答by joe

In addition to the previous answers, with AFNetworking 2.5.0 and iOS7/8 I have found that that the extra step of opening the output stream is also needed to prevent the app from hanging (and eventually crashing from lack of memory).

除了之前的答案,使用 AFNetworking 2.5.0 和 iOS7/8,我发现还需要额外的打开输出流的步骤来防止应用程序挂起(并最终因内存不足而崩溃)。

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