目录
- 创建NSURLSession对象
- NSURLSessionConfiguration详解
- URLSessionTask详解
- NSURLSessionDataTask详解
- NSURLSessionDownloadTask详解
- NSURLSessionUploadTask详解
- 断点续传
序言
在iOS9.0之后,以前使用的NSURLConnection过期,苹果推荐使用NSURLSession来替换NSURLConnection完成网路请求相关操作。NSURLSession的使用非常简单,只需要三个步骤。
- 1.创建NSURLSession对象
- 2.通过 NSURLSession 的实例创建 Task
- 3.执行 Task
一 创建NSURLSession对象
- 通过单例获取
@property (class, readonly, strong) NSURLSession *sharedSession;
- 通过工厂方法获取
// 不用代理
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
// 使用代理
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(id <NSURLSessionDelegate>)delegate delegateQueue:(NSOperationQueue *)queue;
实例代码
// 创建 session 对象
- (void)createSession {
// 1.单例
NSURLSession *session = [NSURLSession sharedSession];
// 2.工厂方法 - 不使用代理
NSURLSession *session1 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
// 3.工厂方法 - 使用代理
NSURLSession *session2 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
}
在使用自定义方式创建NSURLSession对像时,都需要传入一个
NSURLSessionConfiguration
参数,这个参数是对Session的网络请求的基本配置
。那这个NSURLSessionConfiguration都有哪些配置呢?
二 NSURLSessionConfiguration详解
有三个方法来创建NSURLSessionConfiguration:
@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
// macos(10.10), ios(8.0), watchos(2.0), tvos(9.0)
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier;
解释说明
-
defaultSessionConfiguration
使用全局的cache,cookie,使用硬盘来缓存数据 -
ephemeralSessionConfiguration
临时session配置,与默认配置相比,这个配置不会将缓存、cookie等存在本地,只会存在内存里,所以当程序退出时,所有的数据都会消失 -
backgroundSessionConfigurationWithIdentifier:
后台session配置,与默认配置类似,不同的是会在后台开启另一个线程来处理网络数据
一旦创建了NSURLSessionConfiguration就可以给它设置各种属性
下面对NSURLSessionConfiguration
相关属性介绍 - 摘抄别人的
@interface NSURLSessionConfiguration : NSObject <NSCopying>
/* 三种创建方式 */
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0);
/* 当使用上述第三种方式创建后台sessionConfiguration时可以读到初始化时传入的唯一标识,其他创建方式都为空 */
@property (nullable, readonly, copy) NSString *identifier;
/*
缓存策略,默认值是NSURLRequestUseProtocolCachePolicy
*/
@property NSURLRequestCachePolicy requestCachePolicy;
/* 给request指定每次接收数据超时间隔,如果下一次接受新数据用时超过该值,则发送一个请求超时给该request。默认为60s */
@property NSTimeInterval timeoutIntervalForRequest;
/* 给指定resource设定一个超时时间,resource需要在时间到达之前完成。默认是7天。 */
@property NSTimeInterval timeoutIntervalForResource;
/* 指定网络传输类型。精切指出传输类型,可以让系统快速响应,提高传输质量,延长电池寿命等。
typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType)
{
NSURLNetworkServiceTypeDefault = 0, // 普通网络传输,默认使用这个
NSURLNetworkServiceTypeVoIP = 1, // 网络语音通信传输,只能在VoIP使用
NSURLNetworkServiceTypeVideo = 2, // 影像传输
NSURLNetworkServiceTypeBackground = 3, // 网络后台传输,优先级不高时可使用。对用户不需要的网络操作可使用
NSURLNetworkServiceTypeVoice = 4 // 语音传输
};
*/
@property NSURLRequestNetworkServiceType networkServiceType;
/* 是否使用蜂窝网络,默认是yes. */
@property BOOL allowsCellularAccess;
/* 是否由系统根据性能自动裁量后台任务。默认值是NO。同sessionSendsLaunchEvent一样,只对后台configuration有效。 */
@property (getter=isDiscretionary) BOOL discretionary NS_AVAILABLE(10_10, 7_0);
/*
如果要为app的插件提供session,需要给这个值赋值
*/
@property (nullable, copy) NSString *sharedContainerIdentifier NS_AVAILABLE(10_10, 8_0);
/*
表示当后台传输结束时,是否启动app.这个属性只对 后台sessionConfiguration 生效,其他configuration类型会自动忽略该值。默认值是YES。
*/
@property BOOL sessionSendsLaunchEvents NS_AVAILABLE(NA, 7_0);
/*
指定了会话连接中的代理服务器。同样地,大多数面向消费者的应用程序都不需要代理,所以基本上不需要配置这个属性,默认为NULL
*/
@property (nullable, copy) NSDictionary *connectionProxyDictionary;
/* 确定是否支持SSLProtocol版本的会话
*/
@property SSLProtocol TLSMinimumSupportedProtocol;
/*
确定是否支持SSLProtocol版本的会话
*/
@property SSLProtocol TLSMaximumSupportedProtocol;
/*
它可以被用于开启HTTP管道,这可以显着降低请求的加载时间,但是由于没有被服务器广泛支持,默认是禁用的
*/
@property BOOL HTTPShouldUsePipelining;
/*
默认为yes,是否提供来自shareCookieStorge的cookie,如果想要自己提供cookie,可以使用HTTPAdditionalHeaders来提供。
*/
@property BOOL HTTPShouldSetCookies;
/* Policy for accepting cookies. This overrides the policy otherwise specified by the cookie storage. */
@property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy;
/*
指定了一组默认的可以设置出站请求的数据头。这对于跨会话共享信息,如内容类型,语言,用户代理,身份认证,是很有用的。
例如:
@{@"Accept": @"application/json",
@"Accept-Language": @"en",
@"Authorization": authString,
@"User-Agent": userAgentString
}
*/
@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;
/*
同时连接一个host的最大数。iOS默认是4.APP是作为一个整体来看的
*/
@property NSInteger HTTPMaximumConnectionsPerHost;
/*
存储cookie,清除存储,直接set为nil即可。
对于默认和后台的session,使用sharedHTTPCookieStorage。
对于短暂的session,cookie仅仅储存到内存,session失效时会自动清除。
*/
@property (nullable, retain) NSHTTPCookieStorage *HTTPCookieStorage;
/*
证书存储,如果不使用,可set为nil.
默认和后台session,默认使用的sharedCredentialStorage.
短暂的session使用一个私有存储在内存中。session失效会自动清除。
*/
@property (nullable, retain) NSURLCredentialStorage *URLCredentialStorage;
/*
缓存NSURLRequest的response。
默认的configuration,默认值的是sharedURLCache。
后台的configuration,默认值是nil
短暂的configuration,默认一个私有的cache于内存,session失效,cache自动清除。
*/
@property (nullable, retain) NSURLCache *URLCache;
/* Enable extended background idle mode for any tcp sockets created. Enabling this mode asks the system to keep the socket open
* and delay reclaiming it when the process moves to the background (see https://developer.apple.com/library/ios/technotes/tn2277/_index.html)
*/
@property BOOL shouldUseExtendedBackgroundIdleMode NS_AVAILABLE(10_11, 9_0);
/*
处理NSURLRequest的NSURLProtocol的子类。
重要:对后台Session失效。
*/
@property (nullable, copy) NSArray<Class> *protocolClasses;
@end
掌握NSURLSessionConfiguration
参数,那我们就可以创建一个session
对象,然后通过它发送网络请求了。
三 URLSessionTask详解
NSURLSessionTask是一个抽象类,其下有4个实体子类可以直接使用
- NSURLSessionDataTask
- NSURLSessionUploadTask
- NSURLSessionDownloadTask
- NSURLSessionStreamTask
这四个子类封装了现代程序四个最基本的网络任务:获取数据,比如JSON或者XML,上传文件和下载文件还有数据流的获取。
看看类的声明
- NSURLSessionDataTask
// NSURLSessionDataTask
@interface NSURLSessionDataTask : NSURLSessionTask
@end
- NSURLSessionUploadTask
// NSURLSessionUploadTask
@interface NSURLSessionUploadTask : NSURLSessionDataTask
@end
- NSURLSessionDownloadTask
// NSURLSessionDownloadTask
@interface NSURLSessionDownloadTask : NSURLSessionTask
- (void)cancelByProducingResumeData:(void (^)(NSData * _Nullable resumeData))completionHandler;
@end
- NSURLSessionStreamTask
@interface NSURLSessionStreamTask : NSURLSessionTask
- (void)readDataOfMinLength:(NSUInteger)minBytes maxLength:(NSUInteger)maxBytes timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSData * _Nullable data, BOOL atEOF, NSError * _Nullable error))completionHandler;
- (void)writeData:(NSData *)data timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSError * _Nullable error))completionHandler;
- (void)captureStreams;
- (void)closeWrite;
- (void)closeRead;
- (void)startSecureConnection;
- (void)stopSecureConnection;
@end
下面是一幅总结图
NSURLSessionTask.pngNSURLSession比NSURLConnection最方便的地方就是任务可以暂停
,继续
。在网络请求中,真正去执行下载或者上传任务的就是URLSessionTask
,我们来看一下它常用的方法:
-
- (void)resume;
当使用NSURLSession创建一个NSURLSessionTask任务时,要手动调用此方法,任务才会开启,而NSURLConnection默认开启。 -
- (void)suspend;
暂停任务方法,手动调用会暂停。当前任务,再次开启此任务时,会从紧接上次任务开始,会面会说到如何暂停任务再开启任务。 -
- (void)cancel;
取消任务。
NSURLSessionTask还有一个属性
// The current state of the task within the session.
@property (readonly) NSURLSessionTaskState state;
typedef NS_ENUM(NSInteger, NSURLSessionTaskState) {
NSURLSessionTaskStateRunning = 0, /* 正在执行 The task is currently being serviced by the session */
NSURLSessionTaskStateSuspended = 1, // 暂停状态
NSURLSessionTaskStateCanceling = 2, /* 取消状态 The task has been told to cancel. The session will receive a URLSession:task:didCompleteWithError: message. */
NSURLSessionTaskStateCompleted = 3, /* 任务完成状态 The task has completed and the session will receive no more delegate notifications */
} NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);
上面说到的四个类,都直接或间接继承NSURLSessionTask
,所有NSURLSessionTask的方法或者属性这四个类都有,接下来详细介绍这四个类。
3.1 NSURLSessionDataTask
NSURLSessionDataTask是开发中使用频率最高的,我们平常使用的GET和POST请求都是通过它来实现的,如果请求的数据简单并且不需要对获取的数据进行复杂操作,我们使用 Block 解析返回的数据即可。具体代码如下:
GET 请求
- (void)sessionDataTaskGet {
// 1.请求路径
NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/gaoshilist"];
// 2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.创建 session 对象
NSURLSession *session = [NSURLSession sharedSession];
// 4.普通任务 - get
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse * response, NSError *error) {
if (error) {
NSLog(@"NSURLSessionDataTaskerror:%@",error);
return;
}
//5.解析数据
NSLog(@"NSURLSessionDataTask:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}];
// 启动任务
[dataTask resume];
}
运行结果
NSURLSessionDataTask-Get.pngPOST请求
- (void)sessionDataTaskPost {
// 1.请求路径
NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/fankui"];
// 2.创建请求对象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置 post 请求方式
request.HTTPMethod = @"POST";
// 设置请求体
request.HTTPBody = [@"username=1234&pwd=4321" dataUsingEncoding:NSUTF8StringEncoding];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"NSURLSessionDataTaskerror:%@",error);
return;
}
//5.解析数据
NSLog(@"NSURLSessionDataTask:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}];
[dataTask resume];
}
运行结果
NSURLSessionDataTask-post.png代理实现
另外我们也可以设置session的代理来实时的监听数据
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(id <NSURLSessionDelegate>)delegate delegateQueue:(NSOperationQueue *)queue;
它有4个直接或间接的子协议
- NSURLSessionTaskDelegate
- NSURLSessionDownloadDelegate
- NSURLSessionStreamDelegate
- NSURLSessionDataDelegate
实例代码如下
- (void)sessionDataTaskPostDelegate {
// 1.请求路径
NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/fankui"];
// 2.创建请求对象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置 post 请求方式
request.HTTPMethod = @"POST";
// 设置请求体
request.HTTPBody = [@"username=1234&pwd=4321" dataUsingEncoding:NSUTF8StringEncoding];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
}
NSURLSessionDataDelegate协议方法
// 1.接收到服务器的响应
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
NSLog(@"didReceiveResponse");
// 必须设置对响应进行允许处理才会执行后面两个操作。
completionHandler(NSURLSessionResponseAllow);
}
// 2.接收到服务器的数据(可能调用多次)
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
NSLog(@"接受到服务器的数据:%lu",data.length);
}
// 3.请求成功或者失败(如果失败,error有值)
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (error) {
NSLog(@"请求失败: %@",error.description);
} else {
NSLog(@"请求成功");
}
}
运行结果如下
NSURLSessionDataDelegate.png3.2 NSURLSessionDownloadTask
NSURLSessionDownloadTask在下载文件的时候,是将数据一点点地写入本地的临时文件。所以在 completionHandler 这个 block 里,我们需要把文件从一个临时地址移动到一个永久的地址保存起来:
- 实例代码
- (void)sessionDownloadTask {
// 1.请求路径
NSURL *url = [NSURL URLWithString:@"http://www.pptbz.com/pptpic/UploadFiles_6909/201203/2012031220134655.jpg"];
// 2.创建 session 对象
NSURLSession *session = [NSURLSession sharedSession];
// 下载 task
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
// 获取沙盒的 caches 路径
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
// 生成 url 路径
NSURL *url = [NSURL fileURLWithPath:path];
// 将文件保存到指定文件目录下
[[NSFileManager defaultManager] moveItemAtURL:location toURL:url error:nil];
NSLog(@"path = %@",path);
NSLog(@"%@",[NSThread currentThread]);
//切记当前为子线程,
dispatch_async(dispatch_get_main_queue(), ^{
self.imgView.image = [UIImage imageNamed:path];
});
}];
[task resume];
}
运行结果
image.png image.png通过代理方法下载
#pragma mark - sessionDownloadTaskDelegate
- (void)sessionDownloadTaskDelegate {
// 1.请求路径
// NSURL *url = [NSURL URLWithString:@"http://www.pptbz.com/pptpic/UploadFiles_6909/201203/2012031220134655.jpg"];
NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V5.4.0.dmg"];
// 2.创建带有代理方法的自定义 session
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 3.创建任务
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url];
// 4. 开启任务
[task resume];
}
#pragma mark - NSURLSessionDownloadDelegate
/**
* 写入临时文件时调用
* @param bytesWritten 本次写入大小
* @param totalBytesWritten 已写入文件大小
* @param totalBytesExpectedToWrite 请求的总文件的大小
*/
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
//可以监听下载的进度
CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
NSLog(@"downloadTask %f",progress);
}
// 下载完成调用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
// location 还是一个临时路径,需要自己挪到需要的路径(caches 文件夹)
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
NSLog(@"downloadTask 移动文件路径");
}
执行结果
image.png image.png image.png3.3 断点续传
在开发中,我们经常由于某种原因,在下载或上传的时候往往不能一次性下载或上传完,有可能下载或上传了一半就终止了,这时候当条件满足继续下载或上传时,我们不希望从头开始,这时候就可以使用断点续传。它的大概思路是:
-
某种限制,续传暂停
-
将暂停后数据(当前数据)保存起来--_resumeData = resumeData;
-
条件允许续传时,使用resumeData创建新的NSURLSessionTask
-
实例代码如下
/** 进度条*/
@property(nonatomic,strong)UIView *progressView;
/** 进度值*/
@property(nonatomic,strong)UILabel *progressLbe;
/** downloadtask*/
@property(nonatomic,strong)NSURLSessionDownloadTask *downloadTask;
/** data*/
@property(nonatomic,strong)NSData *resumeData;
/** session*/
@property(nonatomic,strong)NSURLSession *session;
- 下载和取消按钮操作
#pragma mark - 按钮点击
// 开始下载
- (void)tapDownload {
// 1.URL
NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V5.4.0.dmg"];
if (self.resumeData) { // 之前已经下载过了
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
} else {
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.downloadTask = [self.session downloadTaskWithRequest:request];
}
[self.downloadTask resume];
}
// 暂停下载
- (void)tapSuspend {
if (self.downloadTask) {
__weak typeof (self)weakSelf = self;
[self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
NSLog(@"resumeData:%@",resumeData);
weakSelf.resumeData = resumeData;
weakSelf.downloadTask = nil;
}];
}
}
// 恢复
- (void)tapRecover {
self.downloadTask = nil;
self.session = nil;
self.resumeData = nil;
self.progressLbe.text = @"0";
CGRect frame = CGRectMake(0, 0, kScreanWidth * 0.6 * 0, 20);
self.progressView.frame = frame;
}
- NSURLSessionDownloadDelegate
#pragma mark - NSURLSessionDownloadDelegate
/**
* 写入临时文件时调用
* @param bytesWritten 本次写入大小
* @param totalBytesWritten 已写入文件大小
* @param totalBytesExpectedToWrite 请求的总文件的大小
*/
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
//可以监听下载的进度
CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
dispatch_async(dispatch_get_main_queue(), ^{
self.progressLbe.text = [NSString stringWithFormat:@"%.2f",progress];
CGRect frame = CGRectMake(0, 0, kScreanWidth * 0.6 * progress, 20);
self.progressView.frame = frame;
});
}
// 下载完成调用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
// location 还是一个临时路径,需要自己挪到需要的路径(caches 文件夹)
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
NSLog(@"downloadTask 移动文件路径");
}
运行结果
断点下载.gif3.4 NSURLSessionUploadTask
在 NSURLSession 中,文件上传主要使用五种方式:
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;
下面我们介绍使用uploadTaskWithRequest:fromData
表单的形式上传数据
- 发送请求
// 发送请求
- (void)sessionUploadTask {
NSURL *url = [NSURL URLWithString:@"https://api.weibo.com/2/statuses/public_timeline.json"];
// 请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置一些参数
[request setHTTPMethod:@"POST"];
//设置请求体
[request setValue:[NSString stringWithFormat: @"multipart/form-data;%@", @"cs"] forHTTPHeaderField:@"Content-type"];
//获取上传的图片的data
NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"picture" ofType:@"jpg"]];
//此处添加需要看清楚内容
NSData *body = [self httpFormDataBodyWithBoundary:@"cs" params:@{@"access_token":@"2.00cYYKWF6EKpiB3883361b1dJiZ4eD",@"status":@"哈哈,这是我测试NSURLSession上传文件的微博"} fieldName:@"pic" fileName:@"pic.png" fileContentType:@"image/png" data:data];
// 发送请求
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"error = %@",error.description);
} else {
NSLog(@"upload success");
}
}];
[uploadTask resume];
}
- 拼接请求体
- (NSData *)httpFormDataBodyWithBoundary:(NSString *)boundary
params:(NSDictionary *)params
fieldName:(NSString *)fieldName
fileName:(NSString *)fileName
fileContentType:(NSString *)fileContentType
data:(NSData *)fileData {
NSString *preBoundary = [NSString stringWithFormat:@"--%@",boundary];
NSString *endBoundary = [NSString stringWithFormat:@"--%@--",boundary];
NSMutableString *body = [[NSMutableString alloc] init];
//遍历
for (NSString *key in params) {
//得到当前的key
//如果key不是当前的pic,说明value是字符类型,比如name:Boris
//添加分界线,换行,必须使用\r\n
[body appendFormat:@"%@\r\n",preBoundary];
//添加字段名称换2行
[body appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];
//添加字段值
[body appendFormat:@"%@\r\n",[params objectForKey:key]];
}
//添加分界线,换行
[body appendFormat:@"%@\r\n",preBoundary];
//声明pic字段,文件名为boris.png
[body appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",fieldName,fileName];
//声明上传文件的格式
[body appendFormat:@"Content-Type: %@\r\n\r\n",fileContentType];
//声明结束符
NSString *endStr = [NSString stringWithFormat:@"\r\n%@",endBoundary];
//声明myRequestData,用来放入http body
NSMutableData *myRequestData = [NSMutableData data];
//将body字符串转化为UTF8格式的二进制
[myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];
//将image的data加入
[myRequestData appendData:fileData];
//加入结束符--hwg--
[myRequestData appendData:[endStr dataUsingEncoding:NSUTF8StringEncoding]];
return myRequestData;
}
执行结果
image.png这里我们需要拼接一个表单数据,才能够上传数据。 当然,我们也可以用代理方法来监听上传的进度。
本文参考
NSURLSession与NSURLConnection区别
更多相关文章参考
iOS-NSURLSession与NSURLConnection区别
iOS-NSURLConnection使用详解
网友评论