总结在前:
1. MKN封装了GET和POST参数,直接用Dictionary对象传入即可;而AFN需要自己手动组装NSURLRequest对象
2. MKN有超时设置;AFN在GET条件下设置的NSURLRequest能起作用,但在POST条件下不启用(原因是apple内部机制,固定为240s)
3. MKN自带有线程池(wifi时最大数为6;wwan时最大数为2);AFN需要自定义线程池
4. 两者使用的方式基本一直,甚至连代码的行数都能一一对应。
5. MKN更新进度时的BLOCK参数直接就是进度的百分比;而AFN是三个参数:当前交互数据量、已经交互累计数据量、总的需要交互的数据量,然后自己计算progress
6. 都是采用异步操作方式,没有同步!(需要同步操作的话,只有采用最原始的NSURLConnection和NSString的静态下载方法)
7. 都有JSON和XML解析专用方法;image异步下载专用方法
8. AFN的AFHTTPClient相当于MKN的MKNetworkEngine,封装了一些简单方法,但没有MKN集成度高
AFN源码:https://github.com/AFNetworking/AFNetworking
AFNQA:https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ
一、MKN vs AFN 下载数据
//----------------------------- //---------MKN下载数据---------- //----------------------------- MKNetworkEngine *MKN = [[MKNetworkEngine alloc] initWithHostName:nil customHeaderFields:nil];//自带了缓存策略;线程池(wifi最大6,wwan最大2);freeze MKNetworkOperation *netOp= [MKN operationWithURLString:downLoadUrl params:nil httpMethod:@"GET"];//继承自NSOperation [netOp addDownloadStream:[NSOutputStream outputStreamToFileAtPath:@"test.pdf" append:NO]];//定义输出流 //----------显示下载进度------------------------------------------------------------------------- MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.view]; [self.view addSubview:HUD]; HUD.tag=1000; HUD.mode = MBProgressHUDModeDeterminate; HUD.labelText = @"正在下载..."; HUD.square = YES; [HUD show:YES]; [netOp onDownloadProgressChanged:^(double progress) {HUD.progress = progress;}];//显示进度条 //-------------------------------------------------------------------------------------------- [netOp onCompletion:^(MKNetworkOperation* completedRequest) {[HUD removeFromSuperview];}//完成 onError:^(NSError* error) {[HUD removeFromSuperview];}]; [MKN enqueueOperation:netOp];//启动线程也可以用[netOp start] //----------------------------- //---------AFN下载数据---------- //----------------------------- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:pdfurl]];//封装下载对象(get,post数据等) //--------封装POST数据,键值对(GET访问就不需要) NSData *postData = [[postString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]dataUsingEncoding:NSUTF8StringEncoding];//将键值对(key=value&key=value)封装为NSData [request setHTTPMethod:@"POST"]; [request setValue:[NSString stringWithFormat:@"%d",[postData length]] forHTTPHeaderField:@"Content-Length"];//设置NSData长度 [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:postData];//设置body //----------------------------- AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];////继承自NSOperation operation.outputStream = [NSOutputStream outputStreamToFileAtPath:BillFile(pdfNameExt) append:NO];//定义输出流 //----------显示下载进度------------------------------------------------------------------------- MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.view]; [self.view addSubview:HUD]; HUD.tag=1000; HUD.mode = MBProgressHUDModeDeterminate; HUD.labelText = @"正在下载..."; HUD.square = YES; [HUD show:YES]; [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {//显示进度条 HUD.progress = (totalBytesRead*1.0) / totalBytesExpectedToRead;}]; //-------------------------------------------------------------------------------------------- [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {[HUD removeFromSuperview];} //完成 failure:^(AFHTTPRequestOperation *operation, NSError *error) {[HUD removeFromSuperview];}]; [operation start];//这里可以自定义一个线程池NSOperationQueue,然后设置最大线程数,调用addOperation
二、MKN vs AFN 上传数据
//----------------------------- //---------MKN上传数据---------- //----------------------------- MKNetworkEngine *MKN = [[MKNetworkEngine alloc] initWithHostName:nil]; MKNetworkOperation *netOp = [MKN operationWithURLString:uploadUrl params:[NSDictionary dictionaryWithObjectsAndKeys:AppSession.deviceId,@"deviceId",nil] httpMethod:@"POST"]; [netOp addFile:BillFile(newBillName) forKey:@"image"];//添加文件 addFilePath:forFileName [netOp setFreezable:YES];//设置保持 //----------显示上传进度------------------------------------------------------------------------- MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.view]; [self.view addSubview:HUD]; HUD.mode = MBProgressHUDModeDeterminate; HUD.labelText = @"正在上传..."; HUD.square = YES; [HUD show:YES]; [netOp onUploadProgressChanged:^(double progress) {HUD.progress = progress;}];//显示进度条 //-------------------------------------------------------------------------------------------- [netOp onCompletion:^(MKNetworkOperation* completedRequest) {[HUD removeFromSuperview];}//完成 onError:^(NSError* error) {[HUD removeFromSuperview];}]; [MKN enqueueOperation:netOp];//启动线程也可以用[netOp start] //----------------------------- //---------AFN上传数据(未测试)---------- //----------------------------- //NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:pdfurl]];// NSData *imageData = UIImagePNGRepresentation(image);//将图片文件转换为NSData(官方只给了图片上传方法,其它任何类型的文件上传有待测试) AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:@"192.168.1.106"]]; NSMutableURLRequest *request = [client multipartFormRequestWithMethod:@"POST" path:@"/upload" parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) { [formData appendPartWithFileData:imageData name:@"avatar" fileName:@"avatar.jpg" mimeType:@"image/jpeg"];}]; AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];////继承自NSOperation //----------显示下载进度------------------------------------------------------------------------- MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.view]; [self.view addSubview:HUD]; HUD.tag=1000; HUD.mode = MBProgressHUDModeDeterminate; HUD.labelText = @"正在下载..."; HUD.square = YES; [HUD show:YES]; [operation setUploadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {//显示进度条 HUD.progress = (totalBytesRead*1.0) / totalBytesExpectedToRead;}]; //-------------------------------------------------------------------------------------------- [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {[HUD removeFromSuperview];} //完成 failure:^(AFHTTPRequestOperation *operation, NSError *error) {[HUD removeFromSuperview];}]; [operation start];//这里可以自定义一个线程池NSOperationQueue,然后设置最大线程数,调用addOperation
三、多线程批量下载文件,没下载完成的后缀为.temp;采用线程池 最大同时运行3个分线程;当下载完成时去掉后缀.temp,并删除临时文件
//函数作用: 多线程批量下载文件,没下载完成的后缀为.temp // 采用线程池 最大同时运行3个分线程 // 当下载完成时去掉后缀.temp,并删除临时文件
//参数:array: 待下载的文件列表,每个文件的描述是NSDictionary,至少包括三个key——filename、filesize、filelink
// path: 待下载文件保存的文件夹路径
//说明:该函数完成后,会发送线程同步消息;FileManager可以在这里(iOS开发知识体系——File Manager)找到源码
- (void)doDownloading:(NSMutableArray *)array toFolder:(NSString *)path{ //---------------------------------过滤不需要下载的文件---------------------------------------------------- NSMutableArray *arrayLocal = [FileManager allFilesAttributeInFolderPath:path];//获取本地目录下所有文件的filename和filesize信息 for (NSDictionary *temp in arrayLocal) {//外循环是本地文件数组 NSString *filename = [temp objectForKey:@"filename"]; NSString *filesize = [temp objectForKey:@"filesize"]; BOOL fileExists = NO; for (NSDictionary *temp1 in array) {//内循环是待下载的文件数组 NSString *filename1 = [temp1 objectForKey:@"filename"]; NSString *filesize1 = [temp1 objectForKey:@"filesize"]; if ([filename1 isEqualToString:filename]) { fileExists = YES; if ([filesize isEqualToString:filesize1]) { //只要文件名和大小一致就表示没必要下载 [array removeObject:temp1]; } break; } } //删除过时的文件 if (!fileExists)[FileManager fileDelete:[path stringByAppendingPathComponent:filename]]; } arrayLocal = nil;//释放内存 //----------------------------------------------------------------------------------------------------- //---------------------------------启动下载线程----------------------------------------------------------- if (array.count>0) { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //线程池 [queue setMaxConcurrentOperationCount:3]; //最大同时运行的线程数 __block int arrayIndex = 0; //用于判断线程池里的线程是否都结束 for (NSDictionary *dictTemp in array) {//遍历目标下载数组并启动下载 NSString *filelink = [dictTemp objectForKey:@"filelink"]; //文件的下载地址 NSString *filename = [dictTemp objectForKey:@"filename"]; //文件名 NSString *filePath = [NSString stringWithFormat:@"%@/%@",path,filename]; //下载后保存文件的绝对路径 NSString *filePathTemp = [NSString stringWithFormat:@"%@/%@.temp",path,filename]; //临时下载的文件路径 AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:filelink]]]; operation.outputStream = [NSOutputStream outputStreamToFileAtPath:filePathTemp append:NO]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {if(![FileManager fileCopy:filePathTemp TargetName:filePath]){[FileManager fileDelete:filePath];} [FileManager fileDelete:filePathTemp]; arrayIndex++; if (arrayIndex==array.count) {[condition signal];}//发送线程同步消息 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { [FileManager fileDelete:filePathTemp]; arrayIndex++; if (arrayIndex==array.count) {[condition signal];}//发送线程同步消息 }]; [queue addOperation:operation]; } }else{ [condition signal];//发送线程同步消息 } //----------------------------------------------------------------------------------------------------- }