iOS NSURLSession
之前阅读过 AFNetworking 源码,今天又拿出来,发现忘记了,就干脆写篇博客记录下相关的知识吧。
1. NSURLSessionConfiguration API
NSURLSessionConfiguration 为 NSURLSession 设置配置,如超时时间还有缓存策略等,要注意,只能设置一次,一旦 URLSession 跑起来,就没有机会更改了。
下面是 API ,
@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
/* identifier for the background session configuration */
@property (nullable, readonly, copy) NSString *identifier;
/* default cache policy for requests */
@property NSURLRequestCachePolicy requestCachePolicy;
/* default timeout for requests. This will cause a timeout if no data is transmitted for the given timeout value, and is reset whenever data is transmitted. */
@property NSTimeInterval timeoutIntervalForRequest;
/* default timeout for requests. This will cause a timeout if a resource is not able to be retrieved within a given timeout. */
@property NSTimeInterval timeoutIntervalForResource;
/* type of service for requests. */
@property NSURLRequestNetworkServiceType networkServiceType;
/* allow request to route over cellular. */
@property BOOL allowsCellularAccess;
/* allow request to route over expensive networks. Defaults to YES. */
@property BOOL allowsExpensiveNetworkAccess API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
/* allow request to route over networks in constrained mode. Defaults to YES. */
@property BOOL allowsConstrainedNetworkAccess API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
/*
* Causes tasks to wait for network connectivity to become available, rather
* than immediately failing with an error (such as NSURLErrorNotConnectedToInternet)
* when it is not. When waiting for connectivity, the timeoutIntervalForRequest
* property does not apply, but the timeoutIntervalForResource property does.
*
* Unsatisfactory connectivity (that requires waiting) includes cases where the
* device has limited or insufficient connectivity for a task (e.g., only has a
* cellular connection but the allowsCellularAccess property is NO, or requires
* a VPN connection in order to reach the desired host).
*
* Default value is NO. Ignored by background sessions, as background sessions
* always wait for connectivity.
*/
@property BOOL waitsForConnectivity API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
/* allows background tasks to be scheduled at the discretion of the system for optimal performance. */
@property (getter=isDiscretionary) BOOL discretionary API_AVAILABLE(macos(10.10), ios(7.0), watchos(2.0), tvos(9.0));
/* The identifier of the shared data container into which files in background sessions should be downloaded.
* App extensions wishing to use background sessions *must* set this property to a valid container identifier, or
* all transfers in that session will fail with NSURLErrorBackgroundSessionRequiresSharedContainer.
*/
@property (nullable, copy) NSString *sharedContainerIdentifier API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
/*
* Allows the app to be resumed or launched in the background when tasks in background sessions complete
* or when auth is required. This only applies to configurations created with +backgroundSessionConfigurationWithIdentifier:
* and the default value is YES.
*/
@property BOOL sessionSendsLaunchEvents API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
/* The proxy dictionary, as described by <CFNetwork/CFHTTPStream.h> */
@property (nullable, copy) NSDictionary *connectionProxyDictionary;
/* The minimum allowable versions of the TLS protocol, from <Security/SecureTransport.h> */
@property SSLProtocol TLSMinimumSupportedProtocol API_DEPRECATED_WITH_REPLACEMENT("TLSMinimumSupportedProtocolVersion", macos(10.9, API_TO_BE_DEPRECATED), ios(7.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED));
/* The maximum allowable versions of the TLS protocol, from <Security/SecureTransport.h> */
@property SSLProtocol TLSMaximumSupportedProtocol API_DEPRECATED_WITH_REPLACEMENT("TLSMaximumSupportedProtocolVersion", macos(10.9, API_TO_BE_DEPRECATED), ios(7.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED));
/* The minimum allowable versions of the TLS protocol, from <Security/SecProtocolTypes.h> */
@property tls_protocol_version_t TLSMinimumSupportedProtocolVersion API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
/* The maximum allowable versions of the TLS protocol, from <Security/SecProtocolTypes.h> */
@property tls_protocol_version_t TLSMaximumSupportedProtocolVersion API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));
/* Allow the use of HTTP pipelining */
@property BOOL HTTPShouldUsePipelining;
/* Allow the session to set cookies on requests */
@property BOOL HTTPShouldSetCookies;
/* Policy for accepting cookies. This overrides the policy otherwise specified by the cookie storage. */
@property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy;
/* Specifies additional headers which will be set on outgoing requests.
Note that these headers are added to the request only if not already present. */
@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;
/* The maximum number of simultanous persistent connections per host */
@property NSInteger HTTPMaximumConnectionsPerHost;
/* The cookie storage object to use, or nil to indicate that no cookies should be handled */
@property (nullable, retain) NSHTTPCookieStorage *HTTPCookieStorage;
/* The credential storage object, or nil to indicate that no credential storage is to be used */
@property (nullable, retain) NSURLCredentialStorage *URLCredentialStorage;
/* The URL resource cache, or nil to indicate that no caching is to be performed */
@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 API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0));
/* An optional array of Class objects which subclass NSURLProtocol.
The Class will be sent +canInitWithRequest: when determining if
an instance of the class can be used for a given URL scheme.
You should not use +[NSURLProtocol registerClass:], as that
method will register your class with the default session rather
than with an instance of NSURLSession.
Custom NSURLProtocol subclasses are not available to background
sessions.
*/
@property (nullable, copy) NSArray<Class> *protocolClasses;
/* multipath service type to use for connections. The default is NSURLSessionMultipathServiceTypeNone */
@property NSURLSessionMultipathServiceType multipathServiceType API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos);
- (instancetype)init API_DEPRECATED("Please use NSURLSessionConfiguration.defaultSessionConfiguration or other class methods to create instances", macos(10.9,10.15), ios(7.0,13.0), watchos(2.0,6.0), tvos(9.0,13.0));
+ (instancetype)new API_DEPRECATED("Please use NSURLSessionConfiguration.defaultSessionConfiguration or other class methods to create instances", macos(10.9,10.15), ios(7.0,13.0), watchos(2.0,6.0), tvos(9.0,13.0));
1. defaultSessionConfiguration : 默认配置,会使用磁盘cache,会保存钥匙串 cookie
2. ephemeralSessionConfiguration :不会存储到磁盘,会把cookie钥匙串等存储到内存,无痕浏览
3. backgroundSessionConfigurationWithIdentifier:当app进入后台依然可以进行会话,根据 identifier 区分,
4. requestCachePolicy : 缓存策略,默认为 NSURLRequestUseProtocolCachePolicy,下面会讲到
5. timeoutIntervalForRequest : 请求的超时时间。默认 60s
6. timeoutIntervalForResource:Resource超时时间 默认7天
7. networkServiceType:网络传输类型 默认 NSURLNetworkServiceTypeDefault,下面会讲到
8. allowsCellularAccess : 是否允许蜂窝数据,默认为 yes
9. allowsExpensiveNetworkAccess:是否允许请求使用昂贵网络,默认为 yes,不知道啥意思
10. allowsConstrainedNetworkAccess:是否允许请求在受限模式网络中进行,默认为yes,不知道啥意思
11. waitsForConnectivity:这个是 iOS11 新加的属性,默认为 NO,如果设置为 yes,在网络连接失败的时候不会立即抛出失败,NSURLErrorNotConnectedToInternet,会等待网络连接可用,在等待网络连接的过程中,timeoutIntervalForRequest 这个超时属性不会生效,timeoutIntervalForResource 属性不影响,不令人满意的连接(需要等待)包括以下情况,设备对一个任务的连接有限制或不足(例如,只有一个蜂窝连接,但allowsCellularAccess属性为NO,或需要一个VPN连接才能到达所需的主机),默认值是NO。被后台会话忽略,因为后台会话总是等待连接。
12. discretionary:允许根据系统的判断来调度后台任务,以获得最佳性能。
13. sharedContainerIdentifier:如果有 App 扩展,用到后台 session,则必需给此属性设置一个有效的 id 值。否则该 session 的所有传输都会失败,并报错 NSURLErrorBackgroundSessionRequiresSharedContainer
14. sessionSendsLaunchEvents:当后台会话中的任务完成时,允许在后台重启或启动应用,或需要验证时。这只适用于使用+backgroundSessionConfigurationWithIdentifier创建的配置:,默认为 yes。
15. connectionProxyDictionary:代理字典,如<CFNetwork/CFHTTPStream.h>所述
16. TLSMinimumSupportedProtocol:TLS协议的最小允许版本,来自<Security/SecureTransport.h>
17. TLSMaximumSupportedProtocol:/* TLS协议的最大允许版本,来自<Security/SecureTransport。h > * /
18. TLSMinimumSupportedProtocolVersion:/* TLS协议的最小允许版本,来自<Security/SecProtocolTypes。h > * /
19. TLSMaximumSupportedProtocolVersion:/* The maximum allowable versions of the TLS protocol, from <Security/SecProtocolTypes.h> */
20. HTTPShouldUsePipelining:/*允许使用HTTP管道*/可显著减少请求的加载时间,是由于没有被服务器广泛支持,默认是 NO
21. HTTPShouldSetCookies:是否允许 session 给 request 设置 cookie,使用的是 HTTPCookieStorage 属性存储的值
22. HTTPCookieAcceptPolicy:接受cookie的策略。这将覆盖由cookie存储指定的策略,覆盖 cookie 存储指定的策略,下面会列举枚举。
23. HTTPAdditionalHeaders:指定将在发送请求时设置的附加头。请注意,只有在请求中没有这些标头时,才会将它们添加到请求中,默认为空,会给所有使用了这个 configuration 的 session 生成的 task 添加额外的请求头,NSURLSession 已经默认给 NSURLRequest 添加一些请求头部字段,包括Authorization、Connection、Host、Proxy-Authenticate、Proxy-Authorization、WWW-Authenticate。因此不要再不要修改这些请求头,可以额外添加的请求头部字段包括Accept、Accept-Language、User-Agent等
24. HTTPMaximumConnectionsPerHost:每个主机的最大同时持久连接数
25. HTTPCookieStorage:要使用的cookie存储对象,或nil,表示不应该处理任何cookie
26. URLCredentialStorage:/*证书存储对象,或nil,表示不使用凭据存储*/
27. URLCache:/* URL资源缓存,或nil,表示不执行缓存*/
28. shouldUseExtendedBackgroundIdleMode:为创建的任何tcp套接字启用扩展的后台空闲模式。启用此模式要求系统保持套接字处于打开状态,并在进程转移到后台时延迟收回套接字(请参阅https://developer.apple.com/library/ios/technotes/tn2277/_index.html)
29. protocolClasses:一个可选的类对象数组,它是NSURLProtocol的子类。类将被发送+canInitWithRequest:当决定类的一个实例是否可以用于一个给定的URL方案时。您不应该使用+[NSURLProtocol registerClass:],因为该方法会将您的类注册到默认会话中,而不是注册到NSURLSession的实例中。自定义NSURLProtocol子类不能用于后台会话。
30. multipathServiceType:/*用于连接的多路径服务类型。默认值是NSURLSessionMultipathServiceTypeNone */
下面是缓存策略的枚举,
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
NSURLRequestUseProtocolCachePolicy = 0,
NSURLRequestReloadIgnoringLocalCacheData = 1,
NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4,
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
NSURLRequestReturnCacheDataElseLoad = 2,
NSURLRequestReturnCacheDataDontLoad = 3,
NSURLRequestReloadRevalidatingCacheData = 5,
};
NSURLRequestUseProtocolCachePolicy : 默认策略,具体的缓存逻辑和协议的声明有关,如果协议没有声明,不需要每次重新验证cache。 如果请求协议头为no-cache,则表现为直接从后台请求数据
NSURLRequestReloadIgnoringLocalCacheData:忽略本地请求,每次都从网络请求
NSURLRequestReloadIgnoringLocalAndRemoteCacheData:忽略本地缓存数据、代理和其他中介的缓存,直接从后台请求数据
NSURLRequestReturnCacheDataElseLoad:优先使用本地缓存,忽略过期时间和请求时长,如果没有本地 cache,则请求网络
NSURLRequestReturnCacheDataDontLoad:只从缓存获取,不进行请求
NSURLRequestReloadRevalidatingCacheData:每次必须重新验证cache
networkServiceType
(1)指定网络传输类型。准确指定传输类型,可让系统快速响应,提高传输质量、延长电池寿命等。
@property NSURLRequestNetworkServiceType networkServiceType;
(2)类型枚举如下
typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType)
{
NSURLNetworkServiceTypeDefault = 0, // 标准网络传输,默认使用,Standard internet traffic
NSURLNetworkServiceTypeVoIP API_DEPRECATED("Use PushKit for VoIP control purposes", macos(10.7,10.15), ios(4.0,13.0), watchos(2.0,6.0), tvos(9.0,13.0)) = 1, // Voice over IP control traffic
NSURLNetworkServiceTypeVideo = 2, // 影像传输 Video traffic
NSURLNetworkServiceTypeBackground = 3, // 后台传输,优先级不高时可使用。对用户不需要的网络操作可使用 Background traffic
NSURLNetworkServiceTypeVoice = 4, // 语音传输 Voice data
NSURLNetworkServiceTypeResponsiveData = 6, // 响应数据 Responsive data
NSURLNetworkServiceTypeAVStreaming API_AVAILABLE(macosx(10.9), ios(7.0), watchos(2.0), tvos(9.0)) = 8 , // Multimedia Audio/Video Streaming
NSURLNetworkServiceTypeResponsiveAV API_AVAILABLE(macosx(10.9), ios(7.0), watchos(2.0), tvos(9.0)) = 9, // Responsive Multimedia Audio/Video
NSURLNetworkServiceTypeCallSignaling API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) = 11, // Call Signaling
};
(1)接受 cookie 的策略
(2)这将重写由 cookie 存储指定的策略
(3)决定了什么情况下 Session 应该接受从服务器发出的 Cookie
@property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy;
(4)枚举如下
typedef NS_ENUM(NSUInteger, NSHTTPCookieAcceptPolicy) {
NSHTTPCookieAcceptPolicyAlways, // 接受所有的cookies
NSHTTPCookieAcceptPolicyNever, // 拒绝所有的cookies
NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain // 只接受从主文档中域的cookie
};
2. NSURLSessionTask
NSURLSessionTask 主要分为三种,NSURLSessionDataTask,NSURLDownloadTask,NSURLUploadTask,其中 upload 属于 dataTask,
1. dataTask:用于请求服务器数据,在内存中存储为 NSData 类型,background session 不支持此 task
2. uploadTask:和 dataTask 类似,只不过在请求的时候增加了 requestBody ,background session 支持
3. downloadTask:下载到磁盘,所有类型的session都支持。
当我们通过 configuration 配置好 session 之后,然后通过工厂来生成不通的 task
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionDataTask * dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:imageURL] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
}];
主要 API
1. - (void)cancel
取消任务;
该方法立即返回,将任务标记为已取消。 一旦任务被标记为被取消,URLSession:task:didCompleteWithError:代理方法将会调用,并给NSURLErrorDomain传递一个错误码NSURLErrorCancelled。 在某些情况下,任务可能会在取消确认之前给其代理发送消息。(不是很懂~~~)
可能会对暂停的任务调用此方法。
2. - (void)resume
对被暂停的任务恢复其执行;
3. - (void)suspend
临时暂停执行任务;
任务暂停时,不会产生网络流量,不会超时。 下载任务可以在以后继续传输数据。 所有其他任务必须重新开始。
4. state
任务的当前状态
NSURLSessionTaskStateRunning = 0
NSURLSessionTaskStateSuspended = 1
NSURLSessionTaskStateCanceling = 2
NSURLSessionTaskStateCompleted = 3
5. priority
处理任务的相对优先级,指定为0.0(最低优先级)和1.0(最高优先级)之间的浮点值。
指定优先级仅提供提示,并不保证性能。 如果不指定优先级,则URL会话任务的优先级为NSURLSessionTaskPriorityDefault,值为0.5。
可以使用三个命名的优先级:NSURLSessionTaskPriorityDefault,NSURLSessionTaskPriorityLow和NSURLSessionTaskPriorityHigh。
我们可以随时指定或更改任务的优先级,但并不是所有网络协议在任务开始后都响应更改。 没有API可以让我们从系统的角度确定任务的有效优先级。
1. countOfBytesExpectedToReceive
期望在响应主体中接收的字节数。
该值基于从服务器接收的Content-Length头部确定。 如果该值不存在,则值为NSURLSessionTransferSizeUnknown。
2. countOfBytesReceived
任务从服务器接收到的response body的字节数。
要在此值更改时收到消息,请执行URLSession:dataTask:didReceiveData:代理方法(用于数据和上传任务)或URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:方法(用于下载任务)。
3. countOfBytesExpectedToSend
任务期望在请求body中发送的字节数。
URL加载系统可以通过三种方式确定上传数据的长度:
a. 从作为上传body提供的NSData对象的长度。
b. 从作为上传任务的上传body(不是下载任务)提供的磁盘上的文件的长度。
c. 从请求对象中的Content-Length,如果我们明确设置它。
否则,如果您提供了流或身体数据对象,则该值为NSURLSessionTransferSizeUnknown(-1),否则为0(0)。
4. countOfBytesSent
任务已发送到请求body到服务器的字节数。
1. currentRequest
当前由任务处理的URL请求对象。
该值通常与初始请求(originalRequest)相同,除非服务器已对初始请求作出响应,重定向到不同的URL。
2. originalRequest
创建任务时传递的原始请求对象。
3. response
服务器对当前请求的响应。
此对象提供有关服务器提供的请求的信息。 此信息始终包含原始URL。 它还可以包括预期长度,MIME类型信息,编码信息,建议的文件名,或这些的组合。
4. taskDescription
对当前任务的描述
5. taskIdentifier
session内任务的唯一标识;
该值仅在单个会话的上下文中是唯一的; 其他会话中的任务可能具有相同的taskIdentifier值。
6. error
任务失败的错误信息;
2.1. NSURLRequest
(instancetype)requestWithURL:(NSURL *)theURL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval
cachePolicy
实现的方式是把NSURLRequest对象映射到NSCachedURLResponse对象。可以设置在内存中缓存的大小,以及在磁盘中缓存的大小和路径。
不是特别需要的话,使用Shared Cached足矣,如果有特别需要,创建一个NSURLCache对象,然后通过+ setSharedURLCache 来设定。
可以设置缓存策略和超时时间,通过NSURLRequest可以设置HTTPMethod,默认是GET
2.2.NSURLResponse
NSURLResponse中包含了metadata,例如返回的数据长度(expectedContentLength),MIME 类型,text编码方式。
NSHTTPURLResponse是NSURLResponse的子类,由于绝大部分的REST都是HTTP的,所以,通常遇到的都是NSHTTPURLResponse对象。通过这个对象可以获得:HTTP的headers,status Code等信息。
其中:HTTP headers包含的信息较多,不懂的可以看看wiki上http headers的内容。
status code会返回请求的状况:例如404是not found。
2.3. NSURLCredential
- 用来处理证书信息
比如用户名密码,比如服务器授权等等。
这个要根据不同的认证方式来处理,
例如以下就是初始化一个用户名密码的认证。
(NSURLCredential *)credentialWithUser:(NSString *)user password:(NSString *)password persistence:(NSURLCredentialPersistence)persistence
typedef NS_ENUM(NSUInteger, NSURLCredentialPersistence) {
NSURLCredentialPersistenceNone, //不存储
NSURLCredentialPersistenceForSession,//按照Session生命周期存储
NSURLCredentialPersistencePermanent,//存储到钥匙串
NSURLCredentialPersistenceSynchronizable//存储到钥匙串,根据相同的AppleID分配到其他设备。
};
2.4. NSURLAuthenticationChallenge
在访问资源的时候,可能服务器会返回需要授权(提供一个NSURLCredential对象)。那么,URLSession:task:didReceiveChallenge:completionHandler:被调用。需要的授权信息会保存在这个类的对象里。
几个常用的属性
error
最后一次授权失败的错误信息
failureResponse
最后一次授权失败的错误信息
previousFailureCount
授权失败的次数
proposedCredential
建议使用的证书
protectionSpace
NSURLProtectionSpace对象,包括了地址端口等信息,接下来会讲解这个对象。
3. NSURLSessionDataTask
数据任务会将服务器返回的数据作为一个或多个NSData对象保存在内存中。 使用数据任务时:
1. 在上传body数据(如果请求有提供)时,session会定期调用其带有状态信息的代理方法URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:。
2. 在收到初始响应后,session将调用其代理的URLSession:dataTask:didReceiveResponse:completionHandler:方法,以便检查状态代码和头部信息,并可选择将数据任务转换为下载任务。
3. 在数据传输过程中,session调用其代理的URLSession:dataTask:didReceiveData:方法,为我们提供服务器返回的数据。
4. 数据接收完成后,session将调用其代理的URLSession:dataTask:willCacheResponse:completionHandler:方法,以确定响应是否应被缓存。
4. NSURLSessionUploadTask
UploadTask继承自DataTask。不难理解,因为UploadTask只不过在Http请求的时候,把数据放到Http Body中。所以,用UploadTask来做的事情,通常直接用DataTask也可以实现
NSURLSessionDataTask的子类;上传任务用于需要请求体(如POST或PUT)的HTTP请求。它们的行为与data task类似,但是我们可以通过在会话中调用不同的方法来创建它们,以便于更容易地提供要上传的内容。与data task一样,如果服务器提供响应,上传任务将该响应作为一个或多个NSData对象返回到内存中。
NOTE:与data task不同,我们可以使用上传任务在后台上传内容。
当我们创建上传任务时,我们需要提供一个NSURLRequest或NSMutableURLRequest对象,该对象包含我们可能需要与上传一起发送的头部信息,例如content type,content disposition等。在iOS中,当我们为后台会话中的文件创建上载任务时,系统会将该文件复制到临时位置,并从那里流出数据。
当上传正在进行时,任务会调用会话代理的URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:方法来定期向我们提供状态信息。
当请求的上传阶段完成时,该任务的行为就像一个数据任务,在会话代理上调用方法来提供服务器的响应头,状态码,内容数据等。
- NSData - 如果对象已经在内存里
使用以下两个函数初始化,Session会自动计算Content-length的Header
通常,还需要提供一些服务器需要的Header,Content-Type就往往需要提供。
uploadTaskWithRequest:fromData:
uploadTaskWithRequest:fromData:completionHandler:
- File-如果对象在磁盘上,这样做有助于降低内存使用。
使用以下两个函数进行初始化,同样,会自动计算Content-Length,如果App没有提供Content-Type,Session会自动创建一个。如果Server需要额外的Header信息,也要提供。
uploadTaskWithRequest:fromFile:
uploadTaskWithRequest:fromFile:completionHandler:
3.Stream
使用这个函数创建
uploadTaskWithStreamedRequest:
注意,这种情况下一定要提供Server需要的Header信息,例如Content-Type和Content-Length。
使用Stream一定要实现这个代理方法,因为Session没办法在重新尝试发送Stream的时候找到数据源。(例如需要授权信息的情况)。这个代理函数,提供了Stream的数据源。
URLSession:task:needNewBodyStream:
4.代理方法
使用这个代理方法获得upload的进度。其他的代理方法
NSURLSessionDataDelegate,NSURLSessionDelegate,NSURLSessionTaskDelegate同样适用于UploadTask
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;
5.上传数据
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://jsonplaceholder.typicode.com/posts"]];
[request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];//这一行一定不能少,因为后面是转换成JSON发送的
[request addValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setHTTPMethod:@"POST"];
[request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
[request setTimeoutInterval:20];
NSDictionary * dataToUploaddic = @{self.keytextfield.text:self.valuetextfield.text};
NSData * data = [NSJSONSerialization dataWithJSONObject:dataToUploaddic
options:NSJSONWritingPrettyPrinted
error:nil];
NSURLSessionUploadTask * uploadtask = [self.session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
self.responselabel.text = dictionary.description;
}else{
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Error" message:error.localizedFailureReason preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
}
- 上传图片
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.freeimagehosting.net/upload.php"]];
[request addValue:@"image/jpeg" forHTTPHeaderField:@"Content-Type"];
[request addValue:@"text/html" forHTTPHeaderField:@"Accept"];
[request setHTTPMethod:@"POST"];
[request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
[request setTimeoutInterval:20];
NSData * imagedata = UIImageJPEGRepresentation(self.imageview.image,1.0);
NSURLSessionUploadTask * uploadtask = [self.session uploadTaskWithRequest:request fromData:imagedata completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString * htmlString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
UploadImageReturnViewController * resultvc = [self.storyboard instantiateViewControllerWithIdentifier:@"resultvc"];
resultvc.htmlString = htmlString;
[self.navigationController pushViewController:resultvc animated:YES];
self.progressview.hidden = YES;
[self.spinner stopAnimating];
[self.spinner removeFromSuperview];
}];
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
self.progressview.progress = totalBytesSent/(float)totalBytesExpectedToSend;
}
5. NSURLSessionDownloadTask
下载任务直接将服务器的响应数据写入临时文件,同时也会提供下载进度的更新。当我们在后台会话中使用下载任务时,即使应用被挂起或其他方式未运行,这些下载任务也会继续进行。
我们可以暂停(取消)下载任务并稍后恢复(假设服务器支持这样做);还可以恢复由于网络连接问题而失败的下载。
使用下载任务时:
1. 在下载期间,会话定期调用代理的带有状态信息的方法:URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:。
2. 成功完成后,会话将调用代理的URLSession:downloadTask:didFinishDownloadingToURL:方法或completionHandler。在该方法中,我们必须打开该文件进行读取或将其移动到应用程序的沙盒目录中保存下来。
3. 在下载失败后,会话将调用委托的URLSession:task:didCompleteWithError:方法或completionHandler。与NSURLSessionDataTask或NSURLSessionUploadTask不同,NSURLSessionDownloadTask将通过HTTP状态码将服务器端错误给相应的NSError对象,如下表格:
1. - (void)cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler
取消下载并在回调中使用resumeData以便之后恢复下载。
completionHandler:
当下载取消成功时被调用。
如果下载是可恢复的,则completionHandler将提供一个resumeData对象。 我们可以稍后将此对象传递到会话的downloadTaskWithResumeData或downloadTaskWithResumeData:completionHandler:方法来创建一个新的任务,以恢复下载的位置。
该block不能保证在特定线程上下文中执行。 因此,我们需要指定适当的调度队列来执行它。
只有满足以下条件,才能恢复下载:
1. 首次请求资源后,资源没有变化
2. 该任务是HTTP或HTTPS GET请求
3. 服务器在其响应中提供ETag或Last-Modified头(或两者)
4. 服务器支持字节范围请求
5. 临时文件尚未被系统删除以缓解磁盘空间压力
self.downloadTask = [self.session downloadTaskWithURL:(NSURL *) completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
}];
断点续传
self.downloadTask = [self.session downloadTaskWithResumeData:(NSData *) completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
}]
[self.downloadTask cancelByProducingResumeData:^(NSData *resumeData)completionHandler]
每次在用上文中的ResumeData创建DownloadTask之后,然后让task开始执行,这个函数就会调用。
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
下载进度
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
下载完成的事件
注意,一定要在这个函数返回之前,对数据进行使用,或者保存
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
例子1
self.downloadTask = [self.session downloadTaskWithURL:(NSURL *) completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
}];
继续上一次保存的数据下载
self.downloadTask = [self.session downloadTaskWithResumeData:(NSData *) completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
}]
这里的ResumeData是通过
[self.downloadTask cancelByProducingResumeData:^(NSData *resumeData)completionHandler]
或者在Session的代理函数的Error中存储,Key是NSURLSessionDownloadTaskResumeData
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
每次在用上文中的ResumeData创建DownloadTask之后,然后让task开始执行,这个函数就会调用。
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
进度
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
完成
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
网友评论