AFN参考资料
http://www.jianshu.com/p/c36159094e24

作者:要上班的斌哥
链接:http://www.jianshu.com/p/c36159094e24
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

最近在写的一个项目里面涉及到资源包的下载操作,由于用户在使用过程中有可能会同时下载多个资源包,那么就需要对下载功能进行设计和封装。最开始使用的是使用AFN的下载方法来进行实现的,不过当时项目需求要求不是太高,所以没有处理一些特殊情况,比如任务数量的控制,优先级还有断点下载等等。就简单的在一个单例Manager里面添加了一个字典,将下载资源包的URL地址作为Key,对应的downloadTask作为Value,这样就可以在想要的地方获取到相应的下载进度了。

@property (nonatomic, strong, nonnull) NSMutableDictionary <NSString *, NSURLSessionDownloadTask *> *downloadTaskDict;

由于现在需要统一管理下载的资源,而且为了表示“用户至上”,比如节约流量需要使用断点下载,包括暂停和继续、应用重启时的断点下载;显示下载速度和比例等等。同时为了控制下载的速度也对最大下载数量进行了限制,默认3个等等。so.....

先说下原理

这里使用了AFN的下载方法来完成下载功能,只不过需要对其进行一些扩展。因此我将每个下载任务封装成了一个模型<FKNetworkingDownloadModel>,以下为部分属性定义:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

NS_CLASS_AVAILABLE_IOS(7_0) @interface FKNetworkingProgressModel : NSObject 

/*
* data length of the bytes written.
*/
@property (nonatomic, assign) int64_t totalBytesWritten;
/*
* the total bytes of the resource data.
*/
@property (nonatomic, assign) int64_t totalBytesExpectedToWrite;
/*
* download speed.
*/
@property (nonatomic, assign) int64_t downloadSpeed;
/*
* download progress.
*/
@property (nonatomic, assign) float downloadProgress;
/*
* download left time
*/
@property (nonatomic, assign) int32_t downloadLeft; @end NS_CLASS_AVAILABLE_IOS(7_0) @interface FKNetworkingDownloadModel : NSObject /*
* resource URLString
*/
@property (nonatomic, copy) NSString *resourceURLString;
/*
* fileName default is resourceURLString last component
*/
@property (nonatomic, copy) NSString *fileName;
/**
* file directory
*/
@property (nonatomic, copy) NSString *fileDirectory;
/**
* file path
*/
@property (nonatomic, copy, nullable) NSString *filePath;
/**
* the plist file path, the plist file include information of the download task mission.
*/
@property (nonatomic, copy, nullable) NSString *plistFilePath;
/**
* record the download time when receive the data from the serverce, used to calculate download speed
*/
@property (nonatomic, strong) NSDate *downloadDate;
/**
* check the download state when a model alloc.
*/
//@property (nonatomic, assign) FKDownloadModelState modelState;
/**
* resume data, marked the position of the download mission.
*/
@property (nonatomic, strong, nullable) NSData *resumeData;
/*
* download task
*/
@property (nonatomic, strong, nullable) NSURLSessionDownloadTask *downloadTask;
/*
* progress
*/
@property (nonatomic, strong, nullable) FKNetworkingProgressModel *progressModel;
/**
* init method
*
* @param URLString resourceURLString
*
* @return
*/
-(instancetype)initWithResourceURLString:(NSString *)URLString; @end NS_ASSUME_NONNULL_END

这样可以将每一个下载的资源封装成一个Model,这样在使用管理类来控制下载的时候就会显得比较轻松。

在使用AFN之前需要补充说明一下NSURLSessionTask的一些知识:
抽象类(父类):NSURLSessionTask 包含了一些属性,其中使用到的属性包括:

//请求信息,包括URL地址等。
@property (nullable, readonly, copy) NSURLRequest *originalRequest;
@property (nullable, readonly, copy) NSURLRequest *currentRequest;
//响应信息,包括响应数据的长度和地址等等
@property (nullable, readonly, copy) NSURLResponse *response;
//下面两个属性是会使用到的,一个是已经接收到的数据长度和总共需要接受的数据长度,根据这个我们可以算出下载的进度信息
@property (readonly) int64_t countOfBytesReceived;
@property (readonly) int64_t countOfBytesExpectedToReceive;
//任务描述,我这里用model对应的URL地址来赋值
@property (nullable, copy) NSString *taskDescription;
//状态(取消、完成、进行中等)
@property (readonly) NSURLSessionTaskState state;

同时父类也提供了几个方法

- (void)cancel;//取消下载任务
- (void)suspend;//挂起(这个一般用于程序在运行中的时候暂停下载任务)
- (void)resume;//恢复下载任务

理论上说,如果不做应用重启后的断点下载,通过上面的步骤已经可以完成大部分的下载操作了,但是在程序重启时并不能够获取到对应的已下载的进度(downloadTask会将下载的资源放入tmp路径下面,以'CFNetworking'开头),那这个时候执行下载任务那么会重新下载。考虑到用户的流量,就必须在重启后的进行断点下载,因此我们需要使用到子类NSURLSessionDownloadTask的一个方法

- (void)cancelByProducingResumeData:(void (^)(NSData * __nullable resumeData))completionHandler;

这个方法可以讲当前的task已下载的数据使用一个data保存起来, 然后使用NSURLSession的方法可以根据这个data从服务器获取后续的数据

- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;

断点下载的原理大概就是这样,接下来是考虑管理类的设计和封装。

管理类的设计和封装

思路:使用单例来管理下载任务,同时可以指定最大的下载数和单任务和多任务模式的切换。关于下载的控制(开始、暂停、恢复和断点下载)都可以通过AFN相应的方法来实现

ANF里面关于下载有几个方法,在<AFURLSessionManager>类里面可以找到
//这个方法是经常用到的一个,生成一个NSURLRequest,然后根据这个请求开始下载任务可以追踪到下载的进度,需要设置下载完成后的文件移动到的位置,最后是完成后的回调信息
-(NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
progress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler; //该方法根据一个resumeData来进行断点下载,我这里断点下载的实现就是根据这个来的,resumeData已经在模型里面了。
在下载cancel或者suspend的时候只需要将model的resumeData赋值,然后写入本地plist文件,下次下载的时候根据plist信息获取下载的一些信息就OK了
-(NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
progress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;

下面附上一头文件中的一些代码

#import <Foundation/Foundation.h>
#import "AFNetworking.h"
#import "FKNetworkingDownloadModel.h" NS_ASSUME_NONNULL_BEGIN NS_CLASS_AVAILABLE_IOS(7_0) @interface FKNetworkingManager : NSObject /**
* download root file path. default is '~/cache/forkid.networking.manager1.0'
*/
@property (nonatomic, copy, readonly) NSString *downloadDirectory; /**
* contains the models whose is downloading.
*/
@property (nonatomic, strong, readonly) NSMutableArray <__kindof FKNetworkingDownloadModel *> *downloadingModels; /**
* contains the models whose is waiting for download.
*/
@property (nonatomic, strong, readonly) NSMutableArray <__kindof FKNetworkingDownloadModel *> *waitingModels; /**
* max download mission number.
*/
@property (nonatomic, assign) NSInteger maxDownloadCount; /**
* first in and fisrt out.
*/
@property (nonatomic, assign) BOOL resumeTaskFIFO; /**
* ignore maxDownloadCount. manager will resume all downloadTask.
*/
@property (nonatomic, assign, getter=isBatchDownload) BOOL batchDownload; /**
* singleton
*/
+(FKNetworkingManager *)shareManager; /**
===============> Description of download start <=============
= when you wanna download a file from serverce, you can use next methods as you need.
= there have some methods such as start, resume, cancel and so on.
= We add the 'cancel' method to pause a task instead of suspend, because we need to resume the task when the App restart.
= all methods will use a download model who is subclass of the 'FKNetworkingDownloadModel' for convenience.
= and every model use a URL string as the primary key to mark a download mission or task.
===============> Description of download end. <=============
*/ /**
* this method used to start a download mission with a download model, notice that the download model can't be nil, or the download mission will not execute.
*
* @param downloadModel download model
* @param progress progress of the download, track to refresh UI and ...
* @param completionHandler you can doing something after download mission completed, such as refresh your UI and move the file and so on.
*/
-(void)fk_startDownloadWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel
progress:(void (^)(FKNetworkingDownloadModel *downloadModel))progress
completionHandler:(void (^)(FKNetworkingDownloadModel *downloadModel, NSError * _Nullable error))completionHandler; /**
* resume a download task with a download model, it will use the download model's 'resumeData'
*
* @param downloadModel download model
*/
-(void)fk_resumeDownloadWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel; /**
* suspend or cancel a download task
*
* @param downloadModel download model
*/
-(void)fk_cancelDownloadTaskWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel; /**
* check the resourece has been downloaded or not from the download model resourceURL.
*
* @param downloadModel download model
*
* @return YES or NO.
*/
-(BOOL)fk_hasDownloadedFileWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel; /**
* delete local file if exist.
*
* @param downloadModel download model.
*/
-(void)fk_deleteDownloadedFileWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel; /**
* delete all downloaded files.
*/
-(void)fk_deleteAllDownloadedFiles; /**
* get a download model, which is downloading with a URLString. if there is not exist a model, will return nil.
*
* @param URLString URLString.
*
* @return download model
*/
-(nullable FKNetworkingDownloadModel *)fk_getDownloadingModelWithURLString:(NSString *)URLString; /**
* get download progress information. such as download speed, progress and so on.
*
* @param downloadModel download model.
*
* @return progress model.
*/
-(nullable FKNetworkingProgressModel *)fk_getDownloadProgressModelWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel;
@end
NS_ASSUME_NONNULL_END

定义完上述的方法后,在实现文件中实现相应的方法即可,因为采用AFN,所以我们不用写太多的步骤,只需要关心流程控制,和线程控制就行了。

下面是部分的实现代码:

#import "FKNetworkingManager.h"
#import "NSObject+FKAdd.h" NSString *const FKNetworkingManagerFileName = @"forkid.networking.manager1.0"; @interface FKNetworkingManager () /**
* AFNetworking manager.
*/
@property (nonatomic, strong) AFHTTPSessionManager *AFManager; /**
* download root directory.
*/
@property (nonatomic, copy) NSString *downloadDirectory; /**
* fileManager to manage download files
*/
@property (nonatomic, strong) NSFileManager *fileManager; /*
* the models for waiting for download, the elements should be FKDownloadModel and it's subClasses
*/
@property (nonatomic, strong) NSMutableArray <__kindof FKNetworkingDownloadModel *> *waitingModels; /*
* the models whose being downloaded, the elements should be FKDownloadModel and it's subClasses
*/
@property (nonatomic, strong) NSMutableArray <__kindof FKNetworkingDownloadModel *> *downloadingModels; /*
* key-values dictionary of the downloadModels, format as '<NSString *key, FKDownloadModel *model>' to make constraints
* used to find a downloadModel from this container,
* when the program will terminate, container will be clear
*/
@property (nonatomic, strong) NSMutableDictionary <NSString *, __kindof FKNetworkingDownloadModel *> *downloadModelsDict; @end NSInteger const fk_timeInterval = 5; @implementation FKNetworkingManager #pragma mark - download methods -(void)fk_startDownloadWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel
progress:(void (^)(FKNetworkingDownloadModel * _Nonnull))progress
completionHandler:(void (^)(FKNetworkingDownloadModel * _Nonnull, NSError * _Nullable))completionHandler{ NSString *fileName = [downloadModel.fileName componentsSeparatedByString:@"."].firstObject;
downloadModel.fileDirectory = [self.downloadDirectory stringByAppendingPathComponent:fileName];
downloadModel.filePath = [[self.downloadDirectory stringByAppendingPathComponent:fileName] stringByAppendingPathComponent:downloadModel.fileName];
downloadModel.plistFilePath = [downloadModel.fileDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", fileName]]; if (![self canBeStartDownloadTaskWithDownloadModel:downloadModel]) return; downloadModel.resumeData = [NSData dataWithContentsOfFile:downloadModel.plistFilePath]; if (downloadModel.resumeData.length == 0) {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadModel.resourceURLString]];
downloadModel.downloadTask = [self.AFManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) { [self setValuesForDownloadModel:downloadModel withProgress:downloadProgress.fractionCompleted];
progress(downloadModel); } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) { return [NSURL fileURLWithPath:downloadModel.filePath]; } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
if (error) {
[self fk_cancelDownloadTaskWithDownloadModel:downloadModel];
completionHandler(downloadModel, error);
}else{
[self.downloadModelsDict removeObjectForKey:downloadModel.resourceURLString];
completionHandler(downloadModel, nil);
[self deletePlistFileWithDownloadModel:downloadModel];
}
}]; }else{ downloadModel.progressModel.totalBytesWritten = [self getResumeByteWithDownloadModel:downloadModel];
downloadModel.downloadTask = [self.AFManager downloadTaskWithResumeData:downloadModel.resumeData progress:^(NSProgress * _Nonnull downloadProgress) { [self setValuesForDownloadModel:downloadModel withProgress:[self.AFManager downloadProgressForTask:downloadModel.downloadTask].fractionCompleted];
progress(downloadModel); } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
return [NSURL fileURLWithPath:downloadModel.filePath];
} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
if (error) {
[self fk_cancelDownloadTaskWithDownloadModel:downloadModel];
completionHandler(downloadModel, error);
}else{
[self.downloadModelsDict removeObjectForKey:downloadModel.resourceURLString];
completionHandler(downloadModel, nil);
[self deletePlistFileWithDownloadModel:downloadModel];
}
}];
} if (![self.fileManager fileExistsAtPath:self.downloadDirectory]) {
[self.fileManager createDirectoryAtPath:self.downloadDirectory withIntermediateDirectories:YES attributes:nil error:nil];
} [self createFolderAtPath:[self.downloadDirectory stringByAppendingPathComponent:fileName]];
[self fk_resumeDownloadWithDownloadModel:downloadModel];
} -(void)fk_resumeDownloadWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
if (downloadModel.downloadTask) {
downloadModel.downloadDate = [NSDate date];
[downloadModel.downloadTask resume];
self.downloadModelsDict[downloadModel.resourceURLString] = downloadModel;
[self.downloadingModels addObject:downloadModel];
}
} -(void)fk_cancelDownloadTaskWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
if (!downloadModel) return;
NSURLSessionTaskState state = downloadModel.downloadTask.state;
if (state == NSURLSessionTaskStateRunning) {
[downloadModel.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
downloadModel.resumeData = resumeData;
@synchronized (self) {
BOOL isSuc = [downloadModel.resumeData writeToFile:downloadModel.plistFilePath atomically:YES];
[self saveTotalBytesExpectedToWriteWithDownloadModel:downloadModel];
if (isSuc) {
downloadModel.resumeData = nil;
[self.downloadModelsDict removeObjectForKey:downloadModel.resourceURLString];
[self.downloadingModels removeObject:downloadModel];
}
}
}];
}
} -(void)fk_deleteDownloadedFileWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
if ([self.fileManager fileExistsAtPath:downloadModel.fileDirectory]) {
[self.fileManager removeItemAtPath:downloadModel.fileDirectory error:nil];
}
} -(void)fk_deleteAllDownloadedFiles{
if ([self.fileManager fileExistsAtPath:self.downloadDirectory]) {
[self.fileManager removeItemAtPath:self.downloadDirectory error:nil];
}
} -(BOOL)fk_hasDownloadedFileWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
if ([self.fileManager fileExistsAtPath:downloadModel.filePath]) {
NSLog(@"已下载的文件...");
return YES;
}
return NO;
} -(FKNetworkingDownloadModel *)fk_getDownloadingModelWithURLString:(NSString *)URLString{
return self.downloadModelsDict[URLString];
} -(FKNetworkingProgressModel *)fk_getDownloadProgressModelWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
FKNetworkingProgressModel *progressModel = downloadModel.progressModel;
progressModel.downloadProgress = [self.AFManager downloadProgressForTask:downloadModel.downloadTask].fractionCompleted;
return progressModel;
} #pragma mark - private methods
-(BOOL)canBeStartDownloadTaskWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
if (!downloadModel) return NO;
if (downloadModel.downloadTask && downloadModel.downloadTask.state == NSURLSessionTaskStateRunning) return NO;
if ([self fk_hasDownloadedFileWithDownloadModel:downloadModel]) return NO;
return YES;
} -(void)setValuesForDownloadModel:(FKNetworkingDownloadModel *)downloadModel withProgress:(double)progress{
NSTimeInterval interval = -1 * [downloadModel.downloadDate timeIntervalSinceNow];
downloadModel.progressModel.totalBytesWritten = downloadModel.downloadTask.countOfBytesReceived;
downloadModel.progressModel.totalBytesExpectedToWrite = downloadModel.downloadTask.countOfBytesExpectedToReceive;
downloadModel.progressModel.downloadProgress = progress;
downloadModel.progressModel.downloadSpeed = (int64_t)((downloadModel.progressModel.totalBytesWritten - [self getResumeByteWithDownloadModel:downloadModel]) / interval);
if (downloadModel.progressModel.downloadSpeed != 0) {
int64_t remainingContentLength = downloadModel.progressModel.totalBytesExpectedToWrite - downloadModel.progressModel.totalBytesWritten;
int currentLeftTime = (int)(remainingContentLength / downloadModel.progressModel.downloadSpeed);
downloadModel.progressModel.downloadLeft = currentLeftTime;
}
} -(int64_t)getResumeByteWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
int64_t resumeBytes = 0;
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:downloadModel.plistFilePath];
if (dict) {
resumeBytes = [dict[@"NSURLSessionResumeBytesReceived"] longLongValue];
}
return resumeBytes;
} -(NSString *)getTmpFileNameWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
NSString *fileName = nil;
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:downloadModel.plistFilePath];
if (dict) {
fileName = dict[@"NSURLSessionResumeInfoTempFileName"];
}
return fileName;
} -(void)createFolderAtPath:(NSString *)path{
if ([self.fileManager fileExistsAtPath:path]) return;
[self.fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
} -(void)deletePlistFileWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
if (downloadModel.downloadTask.countOfBytesReceived == downloadModel.downloadTask.countOfBytesExpectedToReceive) {
[self.fileManager removeItemAtPath:downloadModel.plistFilePath error:nil];
[self removeTotalBytesExpectedToWriteWhenDownloadFinishedWithDownloadModel:downloadModel];
}
} -(NSString *)managerPlistFilePath{
return [self.downloadDirectory stringByAppendingPathComponent:@"ForKidManager.plist"];
} -(nullable NSMutableDictionary <NSString *, NSString *> *)managerPlistDict{
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:[self managerPlistFilePath]];
return dict;
} -(void)saveTotalBytesExpectedToWriteWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
NSMutableDictionary <NSString *, NSString *> *dict = [self managerPlistDict];
[dict setValue:[NSString stringWithFormat:@"%lld", downloadModel.downloadTask.countOfBytesExpectedToReceive] forKey:downloadModel.resourceURLString];
[dict writeToFile:[self managerPlistFilePath] atomically:YES];
} -(void)removeTotalBytesExpectedToWriteWhenDownloadFinishedWithDownloadModel:(FKNetworkingDownloadModel *)downloadModel{
NSMutableDictionary <NSString *, NSString *> *dict = [self managerPlistDict];
[dict removeObjectForKey:downloadModel.resourceURLString];
[dict writeToFile:[self managerPlistFilePath] atomically:YES];
} #pragma mark - share instance
+(FKNetworkingManager *)shareManager{
static FKNetworkingManager *manager = nil;
static dispatch_once_t sigletonOnceToken;
dispatch_once(&sigletonOnceToken, ^{
manager = [[self alloc] init];
});
return manager;
} - (instancetype)init{
self = [super init];
if (self) {
_AFManager = [[AFHTTPSessionManager alloc]init];
_AFManager.requestSerializer.timeoutInterval = 5;
_AFManager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;//NSURLRequestUseProtocolCachePolicy;
NSSet *typeSet = [NSSet setWithObjects:@"application/json", @"text/plain", @"text/javascript", @"text/json", @"text/html", nil];
_AFManager.responseSerializer.acceptableContentTypes = typeSet;
_AFManager.securityPolicy.allowInvalidCertificates = YES; _maxDownloadCount = 1;
_resumeTaskFIFO = YES;
_batchDownload = NO;
_fileManager = [NSFileManager defaultManager];
_waitingModels = [[NSMutableArray alloc] initWithCapacity:1];
_downloadingModels = [[NSMutableArray alloc] initWithCapacity:1];
_downloadModelsDict = [[NSMutableDictionary alloc] initWithCapacity:1]; _downloadDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:FKNetworkingManagerFileName];
[_fileManager createDirectoryAtPath:_downloadDirectory withIntermediateDirectories:YES attributes:nil error:nil]; NSDictionary <NSString *, NSString *> *plistDict = [[NSDictionary alloc] init];
NSString *managerPlistFilePath = [_downloadDirectory stringByAppendingPathComponent:@"ForKidManager.plist"];
[plistDict writeToFile:managerPlistFilePath atomically:YES];
}
return self;
} @end

转自:http://www.jianshu.com/p/f311f7057faa

AFN多文件进度下载的更多相关文章

  1. iOS- 利用AFNetworking3.0+(最新AFN) - 实现文件断点下载

    官方建议AFN的使用方法   0.导入框架准备工作 •1. 将AFNetworking3.0+框架程序拖拽进项目   •2. 或使用Cocopod 导入AFNetworking3.0+   •3.   ...

  2. iOS- 利用AFNetworking(AFN) - 实现文件断点下载

    https://www.cnblogs.com/qingche/p/3500746.html 1. 定义一个全局的AFHttpClient:包含有 1> baseURL 2> 请求 3&g ...

  3. IOS下载查看PDF文件(有下载进度)

    IOS(object-c) 下载查看 PDF 其实还是蛮容易操作的.在下载前,首先要把 IOS 可以保存文件的目录给过一遍: IOS 文件保存目录 IOS 可以自定义写入的文件目录,是很有限的,只能是 ...

  4. 使用 new XMLHttpRequest() 制作下载文件进度条

    mui 进度控件使用方法: 检查当前容器(container控件)自身是否包含.mui-progressbar类: 当前容器包含.mui-progressbar类,则以当前容器为目标控件,直接显示进度 ...

  5. 原生网络请求以及AFN网络请求/异步下载

    这里对网络请求方式做一个总结. 原生方式同步GET请求: NSString *urlStr = @"http://apis.juhe.cn/mobile/get?phone=13429667 ...

  6. iOS- 利用AFNetworking3.0+(最新AFN) - 实现文件上传

    官方建议AFN的使用方法 0.导入框架准备工作 •1. 将AFNetworking3.0+框架程序拖拽进项目   •2. 或使用Cocopod 导入AFNetworking3.0+   •3.  引入 ...

  7. [No00006B]方便的网络下载工具wget 可下载网站目录下的所有文件(可下载整个网站)

    wget是linux下命令行的下载工具,功能很强大,它能完成某些下载软件所不能做的,比如如果你想下载一个网页目录下的所有文件,如何做呢?网络用户有时候会遇到需要下载一批文件的情况,有时甚至需要把整个网 ...

  8. iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄

    前言:本篇讲解,在前篇iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载的基础上,使用输出流代替文件句柄实现大文件断点续传.    在实际开发中,输入输出流用的比较少,但 ...

  9. DE1-SOC的sof文件无法下载解决办法

    按照前面友晶科技的文档介绍一步步的做,后面发现根本无法下载sof文件. 通常思维: 一,器件选错了.器件选择错误会导致sof文件无法下载,至于这个ID具体怎么识别我没有追究.如果是这种错误Quartu ...

随机推荐

  1. 使用Spring boot整合Hive,在启动Spring boot项目时,报错

    使用Spring boot整合Hive,在启动Spring boot项目时,报出异常: java.lang.NoSuchMethodError: org.eclipse.jetty.servlet.S ...

  2. wp8手机浏览器项目

    项目需求如下: 1.页面布局 最上方为搜索/网址框 中间为网页显示区,默认主页为百度搜索 最下方为功能栏,分别有后退,前进,窗口和更多功能 在更多功能中有 分享给好友 发送网址到桌面 查看历史记录等 ...

  3. scss使用后的简单入门总结

    端午节第一天 将之前做的一个小demo的css样式改为了scss 好吧 改完了 赶紧由小兵 升级到中尉了 什么是scss? 我的理解是scss 就是css 的预处理器,使css变得更加富有逻辑. 有什 ...

  4. Python 实现指定目录下 删除指定大小的文件

    import os, sys from stat import * BIG_FILE_THRESHOLD = 6000L #1000000L dict1 = {} # dict2 = {} # def ...

  5. #include <>与#include""区别

    <>先去系统目录中找头文件,如果没有在到当前目录下找.所以像标准的头文件 stdio.h.stdlib.h等用这个方法. 而""首先在当前目录下寻找,如果找不到,再到系 ...

  6. 【Excle数据透视表】如何在数据透视表中使用合并单元格标志

    先有数据透视表如下: 现在看着这个格式不舒服,我们希望调整成如下这种样式 步骤 单击数据透视表任意单元格→右键→数据透视表选项→布局和格式→合并且居中排列带标签的单元格 注意:如果数据透视表报表布局不 ...

  7. 【VBA】显示Excle内置对话框

    点击上图中的"显示Excle内置对话框",显示效果如下: 源代码: Public Sub 显示Excel内置对话框() UserForm.Show End Sub 附件下载

  8. &&与&符号区别

    http://topic.csdn.net/u/20080915/16/f5125300-f69f-4da8-9c3a-a7458590553f.html && 与 &区别: ...

  9. java ee xml 学习

    该文章对j2ee的xml各种标签做了详细全面的说明 http://01121264-163-com.iteye.com/blog/1530063

  10. C----------输入一组整数,求出这组数字子序列和中的最大值,只要求出最大子序列的和,不必求出最大值对应的序列。

    © 版权声明:本文为博主原创文章,转载请注明出处 代码: #include <stdio.h> #include <stdlib.h> #define GET_ARRAY_LE ...