該文章閱讀的AFNetworking的版本爲3.2.0。bash
這個分類提供了爲UIProgressView
控件綁定task
的方法,從而獲取task
的上傳下載進度異步
/**
爲指定的上傳任務綁定進度控件
*/
- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task
animated:(BOOL)animated;
/**
爲指定的下載任務綁定進度控件
*/
- (void)setProgressWithDownloadProgressOfTask:(NSURLSessionDownloadTask *)task
animated:(BOOL)animated;
複製代碼
/**
任務發送字節數量上下文標識
*/
static void * AFTaskCountOfBytesSentContext = &AFTaskCountOfBytesSentContext;
/**
任務接受字節數量上下文標識
*/
static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedContext;
複製代碼
下面的這四個方法就是經過Runtime的關聯對象爲分類添加屬性保存進度條的動畫選項async
- (BOOL)af_uploadProgressAnimated {
return [(NSNumber *)objc_getAssociatedObject(self, @selector(af_uploadProgressAnimated)) boolValue];
}
- (void)af_setUploadProgressAnimated:(BOOL)animated {
objc_setAssociatedObject(self, @selector(af_uploadProgressAnimated), @(animated), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)af_downloadProgressAnimated {
return [(NSNumber *)objc_getAssociatedObject(self, @selector(af_downloadProgressAnimated)) boolValue];
}
- (void)af_setDownloadProgressAnimated:(BOOL)animated {
objc_setAssociatedObject(self, @selector(af_downloadProgressAnimated), @(animated), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
複製代碼
- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task
animated:(BOOL)animated
{
// 若是任務已經執行完了就不繼續向下執行了
if (task.state == NSURLSessionTaskStateCompleted) {
return;
}
// 經過KVO觀察task的state和countOfBytesSent屬性
[task addObserver:self forKeyPath:@"state" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesSentContext];
[task addObserver:self forKeyPath:@"countOfBytesSent" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesSentContext];
// 保存動畫選項
[self af_setUploadProgressAnimated:animated];
}
- (void)setProgressWithDownloadProgressOfTask:(NSURLSessionDownloadTask *)task
animated:(BOOL)animated
{
// 若是任務已經執行完了就不繼續向下執行了
if (task.state == NSURLSessionTaskStateCompleted) {
return;
}
// 經過KVO觀察task的state和countOfBytesReceived屬性
[task addObserver:self forKeyPath:@"state" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesReceivedContext];
[task addObserver:self forKeyPath:@"countOfBytesReceived" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesReceivedContext];
// 保存動畫選項
[self af_setDownloadProgressAnimated:animated];
}
複製代碼
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(__unused NSDictionary *)change
context:(void *)context
{
// 若是是經過這個分類添加的觀察者
if (context == AFTaskCountOfBytesSentContext || context == AFTaskCountOfBytesReceivedContext) {
// 若是是task的countOfBytesSent屬性發生了變化
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
// 若是有要發送的總大小
if ([object countOfBytesExpectedToSend] > 0) {
// 主隊列異步調用
dispatch_async(dispatch_get_main_queue(), ^{
// 計算當前的發送進度併爲控件賦值
[self setProgress:[object countOfBytesSent] / ([object countOfBytesExpectedToSend] * 1.0f) animated:self.af_uploadProgressAnimated];
});
}
}
// 若是是task的countOfBytesReceived屬性發生了變化
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
// 若是有要接受的總大小
if ([object countOfBytesExpectedToReceive] > 0) {
// 主隊列異步調用
dispatch_async(dispatch_get_main_queue(), ^{
// 計算當前的接受進度併爲控件賦值
[self setProgress:[object countOfBytesReceived] / ([object countOfBytesExpectedToReceive] * 1.0f) animated:self.af_downloadProgressAnimated];
});
}
}
// 若是是task的state屬性發生了變化
if ([keyPath isEqualToString:NSStringFromSelector(@selector(state))]) {
// 若是狀態變成了已完成,就移除掉對task屬性的觀察
if ([(NSURLSessionTask *)object state] == NSURLSessionTaskStateCompleted) {
@try {
[object removeObserver:self forKeyPath:NSStringFromSelector(@selector(state))];
if (context == AFTaskCountOfBytesSentContext) {
[object removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))];
}
if (context == AFTaskCountOfBytesReceivedContext) {
[object removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))];
}
}
@catch (NSException * __unused exception) {}
}
}
}
}
複製代碼
能夠看到,綁定進度條控件的功能主要是經過KVO觀察task
的相關屬性實現的,在KVO的回調中更新其進度。post
源碼閱讀系列:AFNetworking動畫
源碼閱讀:AFNetworking(二)——AFURLRequestSerializationspa
源碼閱讀:AFNetworking(三)——AFURLResponseSerialization3d
源碼閱讀:AFNetworking(四)——AFSecurityPolicycode
源碼閱讀:AFNetworking(五)——AFNetworkReachabilityManagerserver
源碼閱讀:AFNetworking(六)——AFURLSessionManager
源碼閱讀:AFNetworking(七)——AFHTTPSessionManager
源碼閱讀:AFNetworking(八)——AFAutoPurgingImageCache
源碼閱讀:AFNetworking(九)——AFImageDownloader
源碼閱讀:AFNetworking(十)——AFNetworkActivityIndicatorManager
源碼閱讀:AFNetworking(十一)——UIActivityIndicatorView+AFNetworking
源碼閱讀:AFNetworking(十二)——UIButton+AFNetworking
源碼閱讀:AFNetworking(十三)——UIImageView+AFNetworking
源碼閱讀:AFNetworking(十四)——UIProgressView+AFNetworking