ios NSURLSession后台传输

http://www.appcoda.com/background-transfer-service-ios7/

http://www.raywenderlich.com/51127/nsurlsession-tutorial

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html

http://blog.csdn.net/kyfxbl/article/details/18629227

http://hayageek.com/ios-nsurlsession-example/

一个很好的IOS学习网站:

http://www.appcoda.com

遇到NSURLSession后台上传文件的问题,得到这个地方的指点:

http://eyeplum.me/2014/02/26/multipart-form-data-background-nsurlsession/ 后解决,非常感谢

具体的实现:

AppDelegate.m中,加入后台处理函数

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{

    self.backgroundTransferCompletionHandler = completionHandler;

}

ViewController.h加入delegate

@interface ViewController : UIViewController <UITableViewDelegate , UITableViewDataSource , NSURLSessionDelegate>

下面是具体的实现,这里任务需要,我们是串行地上传,其实并行上传更方便

//
// ViewController.m
// BackgroundTransfer
//
// Created by feixiang on 16/6/14.
// Copyright (c) 2014 ___FULLUSERNAME___. All rights reserved.
// #import "ViewController.h"
#import "FileUploadInfo.h"
#import "AppDelegate.h" // Define some constants regarding the tag values of the prototype cell's subviews.
#define CellLabelTagValue 10
#define CellStartPauseButtonTagValue 20
#define CellStopButtonTagValue 30
#define CellProgressBarTagValue 40
#define CellLabelReadyTagValue 50 @interface ViewController () @property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSURLSessionUploadTask *task;
@property (nonatomic) BOOL isDoing; @property (nonatomic, strong) NSMutableArray *arrUploadList;
// 文件存放地址
@property (nonatomic, strong) NSString *documentsDirectory; @property (nonatomic, strong) NSString *boundary;
@property (nonatomic, strong) NSString *fileParam;
@property (nonatomic, strong) NSURL *uploadURL;
@property (nonatomic, strong) NSNumber *currentIndex; @end @implementation ViewController - (void)initUploadList{
self.arrUploadList = [[NSMutableArray alloc] init];
NSArray *fileList = [self getFiles:self.documentsDirectory]; for(NSString* file in fileList)
{
NSString* filePath = [self getFilePath:file];
[self.arrUploadList addObject:[[FileUploadInfo alloc] initWithFileTitle:file andFilePath:filePath]];
} } // 继承tableview的函数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return ;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.arrUploadList.count ;
} - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 60.0;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"idCell"];
if( cell == nil ){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"idCell" ];
}
FileUploadInfo *uploader = [self.arrUploadList objectAtIndex:indexPath.row];
UILabel *title = (UILabel *)[cell viewWithTag:CellLabelTagValue];
// 设置属性
title.text = uploader.fileTitle;
return cell ;
} - (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.isDoing = NO ; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
self.documentsDirectory = [paths objectAtIndex:];
self.tblFiles.delegate = self ;
self.tblFiles.dataSource = self ; [self initUploadList];
[self BgUploadInitSession]; } // -------------<feixiang>后台传输函数---------- - (void)BgUploadInitSession{
// 这里加入后台下载功能
// https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.yuanfang"];
// 后台下载用 backgroundSessionConfiguration,先用默认的设置
//NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; //sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil]; // 初始化上传地址
self.boundary = @"----------V2ymHFg03ehbqgZCaKO6jy" ;
self.uploadURL = [NSURL URLWithString:@"http://xxxx/Upload/"]; } - (NSMutableURLRequest *)BgUploadSetHeader{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:self.uploadURL];
[request setHTTPMethod:@"POST"];
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", self.boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"]; return request ;
} - (NSURL *)BgUploadSetUrl:(NSString *)uploadFilePath{
NSData *body = [self BgUploadPrepareData:uploadFilePath] ;
NSString* uploadFile_tmp = [NSString stringWithFormat:@"%@_tmp" ,uploadFilePath ];
[body writeToFile:uploadFile_tmp atomically:true]; // 上传完成后需要将临时文件删除
NSString *filePath = [[NSString stringWithFormat:@"file://%@", uploadFile_tmp] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *fileUrl = [NSURL URLWithString:filePath]; return fileUrl;
} // 这里删除文件有点问题
- (void)BgUploadRemoveTmpFile:(NSString *)tmpFilepath{
tmpFilepath = [NSString stringWithFormat:@"%@_tmp",tmpFilepath];
tmpFilepath = [[NSString stringWithFormat:@"file://%@", tmpFilepath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSFileManager *defaultManager;
defaultManager = [NSFileManager defaultManager];
NSError *error ;
BOOL ret = [defaultManager removeItemAtPath:tmpFilepath error:&error];
if( ret == NO )
NSLog(@"\nerror:%@",error);
} - (NSData*) BgUploadPrepareData:(NSString *)filePath
{
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL fileExists = [fileManager fileExistsAtPath:filePath]; NSMutableData *body = [NSMutableData data];
if( fileExists == YES ){
NSString *fileName = [filePath lastPathComponent]; NSData *dataOfFile = [[NSData alloc] initWithContentsOfFile:filePath]; // 组装POST格式
if (dataOfFile) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", self.boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", fileName] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: application/zip\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:dataOfFile];
[body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", self.boundary] dataUsingEncoding:NSUTF8StringEncoding]];
}
return body;
} - (void)BgUploadCommon:(NSString *)uploadFilePath{
// 由于fromFile会覆盖原来的http请求的body内容。可以先构造一个request,然后将body信息存到文件里面,提供给task调用
// 1 , 构造 HTTP Request POST HEADER
NSMutableURLRequest *request = [self BgUploadSetHeader];
// 2 , 将文件和保存文件form-data信息一起保存到磁盘临时文件中
NSURL *fileUrl = [self BgUploadSetUrl:uploadFilePath];
// 3,使用task的fromFile上传函数
self.task = [self.session uploadTaskWithRequest:request fromFile:fileUrl];
// 启动后台任务,下面回调函数接收消息
[self.task resume];
}
// ----------end 后台传输-------- //----------------各个按钮事件
- (IBAction)startAll:(id)sender{
if( self.isDoing == NO ){
[self.buttonStart setTitle:@"STOP" forState:UIControlStateHighlighted];
self.isDoing = YES;
}else{
[self.buttonStart setTitle:@"START" forState:UIControlStateHighlighted];
self.isDoing = NO;
}
FileUploadInfo *uploader = [self.arrUploadList objectAtIndex:];
[self BgUploadCommon:uploader.filePath];
}
- (IBAction)stopUpload:(id)sender{
if( self.task.state == NSURLSessionTaskStateRunning ){
[self.task suspend];
}
}
- (IBAction)resumeUpload:(id)sender{
if( self.task.state == NSURLSessionTaskStateRunning ){
[self.task resume];
}
} - (IBAction)cancelUpload:(id)sender{
if( self.task.state == NSURLSessionTaskStateRunning ){
[self.task cancel];
}
} //----------------NSURLSession回调函数-------------------------
// 上传进度中
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
NSLog(@"\n%f / %f", (double)totalBytesSent,
(double)totalBytesExpectedToSend); // 更新界面
//int index = [self getIndexWithTaskIdentifier:task.taskIdentifier];
int index = [self.currentIndex intValue];
FileUploadInfo *uploader = [self.arrUploadList objectAtIndex:index]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{
uploader.progress = (double)totalBytesSent / (double)totalBytesExpectedToSend; UITableViewCell *cell = [self.tblFiles cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:]];
UIProgressView *progressView = (UIProgressView *)[cell viewWithTag:CellProgressBarTagValue];
progressView.progress = uploader.progress;
}];
} // 上传完成
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
// 这里继续做下一个任务
[self BgUploadBeginNextTask];
} - (void)BgUploadBeginNextTask{
//int index = [self getIndexWithTaskIdentifier:task.taskIdentifier] + 1 ;
self.currentIndex = @([self.currentIndex intValue] + );
int index = [self.currentIndex intValue];
FileUploadInfo *uploader = [self.arrUploadList objectAtIndex:index]; NSLog(@"\n第 %@ 个任务 %@ 完成 ",self.currentIndex, uploader.filePath); UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = [NSString stringWithFormat:@"%@ have been uploaded!",uploader.filePath];
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification]; //先删除临时文件
[self BgUploadRemoveTmpFile:uploader.filePath];
if( index < [self.arrUploadList count] ){
[self BgUploadCommon:uploader.filePath];
}
} // 后台传输完成,处理URLSession完成事件
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate; // Check if all download tasks have been finished.
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([uploadTasks count] == ) {
if (appDelegate.backgroundTransferCompletionHandler != nil) {
// Copy locally the completion handler.
void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler; // Make nil the backgroundTransferCompletionHandler.
appDelegate.backgroundTransferCompletionHandler = nil; [[NSOperationQueue mainQueue] addOperationWithBlock:^{
completionHandler(); // 这里继续做下一个任务
[self BgUploadBeginNextTask];
}];
}
} }];
} -(int)getIndexWithTaskIdentifier:(unsigned long)taskIdentifier{
int index = ;
for (int i=; i<[self.arrUploadList count]; i++) {
FileUploadInfo *uploader = [self.arrUploadList objectAtIndex:i];
if (uploader.taskIdentifier == taskIdentifier) {
index = i;
break;
}
} return index;
} //----------------END NSURLSession回调函数----------------------- // 获取目录下的所有文件
-(NSArray*)getFiles:(NSString *)dir
{
NSFileManager* fm = [NSFileManager defaultManager];
NSArray* array = [fm contentsOfDirectoryAtPath:dir error:nil ];
NSMutableArray* fileList = [[NSMutableArray alloc]init]; BOOL isDir = NO ;
for(NSString* file in array)
{
[fm fileExistsAtPath:file isDirectory:&isDir];
if( !isDir && ![file isEqualToString:@".DS_Store"])
[fileList addObject:file];
}
return fileList ;
} - (NSString*)getFilePath:(NSString *)filename{
NSString *uploadFilePath = [self.documentsDirectory stringByAppendingPathComponent:filename];
return uploadFilePath;
} - (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} @end

http://numbbbbb.gitbooks.io/-the-swift-programming-language-/

上一篇:jquery $ dollar符号用法总结


下一篇:ThinkPHP登录功能的实现方法