版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2018.02.24 |
前言
我們做APP,文字和圖片是絕對不可缺少的元素,特別是圖片一般存儲在圖床里面,一般公司可以委托第三方保存,NB的公司也可以自己存儲圖片,ios有很多圖片加載的第三方框架,其中最優(yōu)秀的莫過于SDWebImage,它幾乎可以滿足你所有的需求,用了好幾年這個框架,今天想總結(jié)一下。感興趣的可以看其他幾篇。
1. SDWebImage探究(一)
2. SDWebImage探究(二)
3. SDWebImage探究(三)
4. SDWebImage探究(四)
5. SDWebImage探究(五)
6. SDWebImage探究(六) —— 圖片類型判斷深入研究
7. SDWebImage探究(七) —— 深入研究圖片下載流程(一)之有關(guān)option的位移枚舉的說明
8. SDWebImage探究(八) —— 深入研究圖片下載流程(二)之開始下載并返回下載結(jié)果的總的方法
9. SDWebImage探究(九) —— 深入研究圖片下載流程(三)之下載之前的緩存查詢操作
10. SDWebImage探究(十) —— 深入研究圖片下載流程(四)之查詢緩存后的block回調(diào)處理
11. SDWebImage探究(十一) —— 深入研究圖片下載流程(五)之SDWebImageDownloadToken和操作對象的生成和返回
12. SDWebImage探究(十二) —— 深入研究圖片下載流程(六)之下載器到具體下載操作的代理分發(fā)實(shí)現(xiàn)
NSURLSession中的幾種代理
這些代理方法都在NSURLSession中,我們先簡單的看一下該類的功能。
- 通過URL將數(shù)據(jù)下載到內(nèi)存
- 通過URL將數(shù)據(jù)下載到文件系統(tǒng)
- 將數(shù)據(jù)上傳到指定URL
- 在后臺完成上述功能
NSURLSession是下載的上下文,其中包含了很多下載相關(guān)的代理分發(fā),包括NSURLSessionDelegate
、NSURLSessionTaskDelegate <NSURLSessionDelegate>
、NSURLSessionDataDelegate <NSURLSessionTaskDelegate>
、NSURLSessionDownloadDelegate <NSURLSessionTaskDelegate>
、NSURLSessionStreamDelegate <NSURLSessionTaskDelegate>
,它們之間的關(guān)系看繼承就已經(jīng)很清楚了。
它們之間的關(guān)系可以參考下圖:
NSURLSessionDelegate
先看一下API文檔
/*
* Messages related to the URL session as a whole
與整個URL session相關(guān)的消息
*/
@protocol NSURLSessionDelegate <NSObject>
@optional
/* The last message a session receives. A session will only become
* invalid because of a systemic error or when it has been
* explicitly invalidated, in which case the error parameter will be nil.
*/
會話收到的最后一條消息。 一個會話只會因?yàn)橄到y(tǒng)錯誤或者當(dāng)它明確地失效而失效,
在這種情況下,錯誤參數(shù)將為nil。
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error;
/* If implemented, when a connection level authentication challenge
* has occurred, this delegate will be given the opportunity to
* provide authentication credentials to the underlying
* connection. Some types of authentication will apply to more than
* one request on a given connection to a server (SSL Server Trust
* challenges). If this delegate message is not implemented, the
* behavior will be to use the default handling, which may involve user
* interaction.
*/
如果已實(shí)現(xiàn),則在發(fā)生連接級別身份驗(yàn)證質(zhì)詢時,此代理將有機(jī)會向底層連接提供身份驗(yàn)證憑據(jù)。
某些類型的身份驗(yàn)證將適用于給定服務(wù)器連接上的多個請求(SSL服務(wù)器信任SSL Server Trust挑戰(zhàn))。
如果此代理消息未實(shí)現(xiàn),則行為將使用默認(rèn)處理,這可能涉及用戶交互。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
/* If an application has received an
* -application:handleEventsForBackgroundURLSession:completionHandler:
* message, the session delegate will receive this message to indicate
* that all messages previously enqueued for this session have been
* delivered. At this time it is safe to invoke the previously stored
* completion handler, or to begin any internal updates that will
* result in invoking the completion handler.
*/
如果應(yīng)用程序收到了-application:handleEventsForBackgroundURLSession:completionHandler:
消息,則會話代理將收到此消息,指示之前已為此會話入隊(duì)的所有消息已傳遞。 此時,調(diào)用先前存儲的
完成處理程序或開始任何內(nèi)部更新將導(dǎo)致調(diào)用完成處理程序,這一過程是安全的。
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
@end
NSURLSessionTaskDelegate
下面看一下API
/*
* Messages related to the operation of a specific task.
與特定任務(wù)的操作有關(guān)的消息
*/
@protocol NSURLSessionTaskDelegate <NSURLSessionDelegate>
@optional
/*
* Sent when the system is ready to begin work for a task with a delayed start
* time set (using the earliestBeginDate property). The completionHandler must
* be invoked in order for loading to proceed. The disposition provided to the
* completion handler continues the load with the original request provided to
* the task, replaces the request with the specified task, or cancels the task.
* If this delegate is not implemented, loading will proceed with the original
* request.
*
* Recommendation: only implement this delegate if tasks that have the
* earliestBeginDate property set may become stale and require alteration prior
* to starting the network load.
*
* If a new request is specified, the allowsCellularAccess property from the
* new request will not be used; the allowsCellularAccess property from the
* original request will continue to be used.
*
* Canceling the task is equivalent to calling the task's cancel method; the
* URLSession:task:didCompleteWithError: task delegate will be called with error
* NSURLErrorCancelled.
*/
當(dāng)系統(tǒng)準(zhǔn)備好開始工作時設(shè)置延遲的開始時間(使用earliestBeginDate屬性)時發(fā)送。必須調(diào)用
completionHandler才能繼續(xù)加載。提供給完成處理程序的處置將繼續(xù)使用提供給該任務(wù)的原始請求的
負(fù)載,用指定的任務(wù)替換該請求或取消該任務(wù)。如果這個委托沒有實(shí)現(xiàn),加載將繼續(xù)處理原始請求。
建議:如果具有設(shè)置earliestBeginDate屬性的任務(wù)可能會過時并且需要在開始網(wǎng)絡(luò)加載
之前進(jìn)行更改,那么僅實(shí)現(xiàn)此代理。
如果指定了新請求,則不會使用來自新請求的allowsCellularAccess
屬性;來自原始請求的allowsCellularAccess屬性將繼續(xù)使用。
取消任務(wù)等同于調(diào)用任務(wù)的cancel方法; URLSession:task:didCompleteWithError:任務(wù)代理將被調(diào)用,error為NSURLErrorCancelled。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willBeginDelayedRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLSessionDelayedRequestDisposition disposition, NSURLRequest * _Nullable newRequest))completionHandler
API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
/*
* Sent when a task cannot start the network loading process because the current
* network connectivity is not available or sufficient for the task's request.
*
* This delegate will be called at most one time per task, and is only called if
* the waitsForConnectivity property in the NSURLSessionConfiguration has been
* set to YES.
*
* This delegate callback will never be called for background sessions, because
* the waitForConnectivity property is ignored by those sessions.
*/
當(dāng)任務(wù)無法啟動網(wǎng)絡(luò)加載過程時發(fā)送,因?yàn)楫?dāng)前網(wǎng)絡(luò)連接不可用或不足以滿足任務(wù)請求。
每個任務(wù)最多只能調(diào)用一次該委托,并且只有在NSURLSessionConfiguration中
的waitsForConnectivity屬性設(shè)置為YES時才會調(diào)用該代理。
此代理回調(diào)將永遠(yuǎn)不會被后臺會話調(diào)用,因?yàn)檫@些會話會忽略waitForConnectivity屬性。
- (void)URLSession:(NSURLSession *)session taskIsWaitingForConnectivity:(NSURLSessionTask *)task
API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
/* An HTTP request is attempting to perform a redirection to a different
* URL. You must invoke the completion routine to allow the
* redirection, allow the redirection with a modified request, or
* pass nil to the completionHandler to cause the body of the redirection
* response to be delivered as the payload of this request. The default
* is to follow redirections.
*
* For tasks in background sessions, redirections will always be followed and this method will not be called.
*/
一個HTTP請求正試圖執(zhí)行重定向到一個不同的URL。 您必須調(diào)用完成例程以允許重定向,允許使用修改后
的請求進(jìn)行重定向,或?qū)il傳遞給completionHandler以使重定向響應(yīng)的主體作為此請求的有效內(nèi)容傳遞。
默認(rèn)是遵循重定向。
對于后臺會話中的任務(wù),將始終遵循重定向,并且不會調(diào)用此方法。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler;
/* The task has received a request specific authentication challenge.
* If this delegate is not implemented, the session specific authentication challenge
* will *NOT* be called and the behavior will be the same as using the default handling
* disposition.
*/
該任務(wù)已收到請求特定的身份驗(yàn)證質(zhì)詢。 如果這個代理沒有被實(shí)現(xiàn),會話特定的認(rèn)證挑戰(zhàn)不會被調(diào)用,
并且行為將與使用默認(rèn)處理處置相同。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
/* Sent if a task requires a new, unopened body stream. This may be
* necessary when authentication has failed for any request that
* involves a body stream.
*/
如果任務(wù)需要新的未打開的正文流,則發(fā)送。
當(dāng)涉及正文流的任何請求的身份驗(yàn)證失敗時,這可能是必需的。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler;
/* Sent periodically to notify the delegate of upload progress. This
* information is also available as properties of the task.
*/
定期發(fā)送以通知代理上傳進(jìn)度。 該信息也可作為任務(wù)的屬性。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;
/*
* Sent when complete statistics information has been collected for the task.
*/
當(dāng)完成任務(wù)的完整統(tǒng)計信息時發(fā)送。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
/* Sent as the last message related to a specific task. Error may be
* nil, which implies that no error occurred and this task is complete.
*/
作為與特定任務(wù)相關(guān)的最后一條消息發(fā)送。 錯誤可能為nil,
這意味著沒有發(fā)生錯誤,并且此任務(wù)已完成。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error;
@end
NSURLSessionDataDelegate
下面看一下API文檔
/*
* Messages related to the operation of a task that delivers data
* directly to the delegate.
與將數(shù)據(jù)直接傳遞給代理的任務(wù)的操作有關(guān)的消息
*/
@protocol NSURLSessionDataDelegate <NSURLSessionTaskDelegate>
@optional
/* The task has received a response and no further messages will be
* received until the completion block is called. The disposition
* allows you to cancel a request or to turn a data task into a
* download task. This delegate message is optional - if you do not
* implement it, you can get the response as a property of the task.
*
* This method will not be called for background upload tasks (which cannot be converted to download tasks).
*/
該任務(wù)已收到響應(yīng),直到完成塊被調(diào)用不會收到更多消息。 該配置允許您取消請求或?qū)?shù)據(jù)任務(wù)轉(zhuǎn)換
為下載任務(wù)。 此代理消息是可選的 - 如果您沒有實(shí)現(xiàn)它,則可以將響應(yīng)作為任務(wù)的屬性獲取。
此方法不會被后臺上傳任務(wù)(不能轉(zhuǎn)換為下載任務(wù))調(diào)用。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
/* Notification that a data task has become a download task. No
* future messages will be sent to the data task.
*/
通知數(shù)據(jù)任務(wù)已成為下載任務(wù)。 沒有更多的消息將被發(fā)送到數(shù)據(jù)任務(wù)。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;
/*
* Notification that a data task has become a bidirectional stream
* task. No future messages will be sent to the data task. The newly
* created streamTask will carry the original request and response as
* properties.
*
* For requests that were pipelined, the stream object will only allow
* reading, and the object will immediately issue a
* -URLSession:writeClosedForStream:. Pipelining can be disabled for
* all requests in a session, or by the NSURLRequest
* HTTPShouldUsePipelining property.
*
* The underlying connection is no longer considered part of the HTTP
* connection cache and won't count against the total number of
* connections per host.
*/
通知數(shù)據(jù)任務(wù)已成為雙向流任務(wù)。 沒有更多的消息將被發(fā)送到數(shù)據(jù)任務(wù)。 新創(chuàng)建的streamTask將作為屬性攜帶原始請求和響應(yīng)。
對于流水線的請求,流對象只允許讀取,而對象將立即發(fā)出-URLSession:writeClosedForStream :。
對于會話中的所有請求,或者NSURLRequest 的HTTPShouldUsePipelining屬性,都可以禁用管道傳輸。
底層連接不再被認(rèn)為是HTTP連接緩存的一部分,并且不會計入每個主機(jī)的連接總數(shù)。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask;
/* Sent when data is available for the delegate to consume. It is
* assumed that the delegate will retain and not copy the data. As
* the data may be discontiguous, you should use
* [NSData enumerateByteRangesUsingBlock:] to access it.
*/
數(shù)據(jù)可供代理使用時發(fā)送。 假定代理將保留并不復(fù)制數(shù)據(jù)。 由于數(shù)據(jù)可能不連續(xù),因此應(yīng)該
使用[NSData enumerateByteRangesUsingBlock:]來訪問它。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data;
/* Invoke the completion routine with a valid NSCachedURLResponse to
* allow the resulting data to be cached, or pass nil to prevent
* caching. Note that there is no guarantee that caching will be
* attempted for a given resource, and you should not rely on this
* message to receive the resource data.
*/
用有效的NSCachedURLResponse調(diào)用完成例程以允許緩存結(jié)果數(shù)據(jù),或通過nil來防止緩存。
請注意,不能保證將為給定資源嘗試緩存,并且不應(yīng)該依賴此消息來接收資源數(shù)據(jù)。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;
@end
NSURLSessionDownloadDelegate
下面看一下API
/*
* Messages related to the operation of a task that writes data to a
* file and notifies the delegate upon completion.
與將數(shù)據(jù)寫入文件并在完成時通知代理的任務(wù)的操作有關(guān)的消息
*/
@protocol NSURLSessionDownloadDelegate <NSURLSessionTaskDelegate>
/* Sent when a download task that has completed a download. The delegate should
* copy or move the file at the given location to a new location as it will be
* removed when the delegate message returns. URLSession:task:didCompleteWithError: will
* still be called.
*/
當(dāng)完成下載的下載任務(wù)時發(fā)送。 代理應(yīng)該將指定位置的文件復(fù)制或移動到新位置,因?yàn)榇硐⒎祷?時將被刪除。 URLSession:task:didCompleteWithError:仍然會被調(diào)用。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location;
@optional
/* Sent periodically to notify the delegate of download progress. */
定期發(fā)送以通知代理下載進(jìn)度
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
/* Sent when a download has been resumed. If a download failed with an
* error, the -userInfo dictionary of the error will contain an
* NSURLSessionDownloadTaskResumeData key, whose value is the resume
* data.
*/
下載已恢復(fù)時發(fā)送。 如果下載失敗并顯示錯誤,則error的-userInfo字典將包含NSURLSessionDownloadTaskResumeData鍵,其值為恢復(fù)的數(shù)據(jù)。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes;
@end
NSURLSessionStreamDelegate
下面看一下API文檔
@protocol NSURLSessionStreamDelegate <NSURLSessionTaskDelegate>
@optional
/* Indiciates that the read side of a connection has been closed. Any
* outstanding reads complete, but future reads will immediately fail.
* This may be sent even when no reads are in progress. However, when
* this delegate message is received, there may still be bytes
* available. You only know that no more bytes are available when you
* are able to read until EOF. */
指示連接的讀取端已關(guān)閉。 任何未完成的讀取都會結(jié)束,但將來的讀取將立即失敗。即使沒有
讀取正在進(jìn)行,也可能會發(fā)送此信息。 但是,收到此代理消息時,可能仍有可用字節(jié)。
只有在能夠讀取EOF時,您才知道沒有更多的字節(jié)可用。
- (void)URLSession:(NSURLSession *)session readClosedForStreamTask:(NSURLSessionStreamTask *)streamTask;
/* Indiciates that the write side of a connection has been closed.
* Any outstanding writes complete, but future writes will immediately
* fail.
*/
表示連接的寫入端已關(guān)閉。 任何未完成的寫入都會完成,但將來寫入將立即失敗。
- (void)URLSession:(NSURLSession *)session writeClosedForStreamTask:(NSURLSessionStreamTask *)streamTask;
/* A notification that the system has determined that a better route
* to the host has been detected (eg, a wi-fi interface becoming
* available.) This is a hint to the delegate that it may be
* desirable to create a new task for subsequent work. Note that
* there is no guarantee that the future task will be able to connect
* to the host, so callers should should be prepared for failure of
* reads and writes over any new interface. */
系統(tǒng)已經(jīng)確定檢測到到主機(jī)的更好路由的通知(例如,Wi-Fi界面變得可用)。這是對代理的提示,
可能需要為后續(xù)工作創(chuàng)建新任務(wù)。 請注意,不能保證將來的任務(wù)將能夠連接到主機(jī),因此調(diào)用者
應(yīng)該準(zhǔn)備好通過任何新接口進(jìn)行讀寫失敗
- (void)URLSession:(NSURLSession *)session betterRouteDiscoveredForStreamTask:(NSURLSessionStreamTask *)streamTask;
/* The given task has been completed, and unopened NSInputStream and
* NSOutputStream objects are created from the underlying network
* connection. This will only be invoked after all enqueued IO has
* completed (including any necessary handshakes.) The streamTask
* will not receive any further delegate messages.
*/
給定的任務(wù)已完成,未打開的NSInputStream和NSOutputStream對象是從底層網(wǎng)絡(luò)連接創(chuàng)建的。
這只會在所有入隊(duì)的IO完成(包括任何必要的握手)后才會被調(diào)用。streamTask不會接收到
任何進(jìn)一步的代理消息。
- (void)URLSession:(NSURLSession *)session streamTask:(NSURLSessionStreamTask *)streamTask
didBecomeInputStream:(NSInputStream *)inputStream
outputStream:(NSOutputStream *)outputStream;
@end
參考文章
1. NSURLSession的一些代理方法
2. ios NSURLSession使用說明及后臺工作流程分析
后記
本篇已結(jié)束,主要是介紹NSURLSession這幾個代理的關(guān)系以及它們的簡單用法,資料主要來自蘋果的API,后續(xù)會進(jìn)一步結(jié)合SDWebImage等框架和工程實(shí)踐進(jìn)行深化。喜歡的關(guān)注我,待續(xù)~~~