美文网首页AFNetworking源码探究
AFNetworking源码探究(十九) —— UIKit相关之

AFNetworking源码探究(十九) —— UIKit相关之

作者: 刀客传奇 | 来源:发表于2018-03-04 09:01 被阅读28次

版本记录

版本号 时间
V1.0 2018.03.04

前言

我们做APP发起网络请求,都离不开一个非常有用的框架AFNetworking,可以说这个框架的知名度已经超过了苹果的底层网络请求部分,很多人可能不知道苹果底层是如何发起网络请求的,但是一定知道AFNetworking,接下来几篇我们就一起详细的解析一下这个框架。感兴趣的可以看上面写的几篇。
1. AFNetworking源码探究(一) —— 基本介绍
2. AFNetworking源码探究(二) —— GET请求实现之NSURLSessionDataTask实例化(一)
3. AFNetworking源码探究(三) —— GET请求实现之任务进度设置和通知监听(一)
4. AFNetworking源码探究(四) —— GET请求实现之代理转发思想(一)
5. AFNetworking源码探究(五) —— AFURLSessionManager中NSURLSessionDelegate详细解析(一)
6. AFNetworking源码探究(六) —— AFURLSessionManager中NSURLSessionTaskDelegate详细解析(一)
7. AFNetworking源码探究(七) —— AFURLSessionManager中NSURLSessionDataDelegate详细解析(一)
8. AFNetworking源码探究(八) —— AFURLSessionManager中NSURLSessionDownloadDelegate详细解析(一)
9. AFNetworking源码探究(九) —— AFURLSessionManagerTaskDelegate中三个转发代理方法详细解析(一)
10. AFNetworking源码探究(十) —— 数据解析之数据解析架构的分析(一)
11. AFNetworking源码探究(十一) —— 数据解析之子类中协议方法的实现(二)
12. AFNetworking源码探究(十二) —— 数据解析之子类中协议方法的实现(三)
13. AFNetworking源码探究(十三) —— AFSecurityPolicy与安全认证 (一)
14. AFNetworking源码探究(十四) —— AFSecurityPolicy与安全认证 (二)
15. AFNetworking源码探究(十五) —— 请求序列化之架构分析(一)
16. AFNetworking源码探究(十六) —— 请求序列化之协议方法的实现(二)
17. AFNetworking源码探究(十七) —— _AFURLSessionTaskSwizzling实现方法交换(转载)(一)
18. AFNetworking源码探究(十八) —— UIKit相关之AFNetworkActivityIndicatorManager(一)

回顾

上一篇主要讲述了AFNetworkActivityIndicatorManager数据加载指示器。这一篇主要讲述了UIKit的几个分类。


UIActivityIndicatorView+AFNetworking

1. 接口调用

这个是指示器的一个分类,看一下.h接口。

@interface UIActivityIndicatorView (AFNetworking)

///----------------------------------
/// @name Animating for Session Tasks
///----------------------------------

/**
 Binds the animating state to the state of the specified task.

 @param task The task. If `nil`, automatic updating from any previously specified operation will be disabled.
 */
- (void)setAnimatingWithStateOfTask:(nullable NSURLSessionTask *)task;

@end

将动画状态绑定到指定任务的状态。这里的参数Task,如果为nil,则从先前指定的操作的自动更新将被禁用。

这里只有上面一个暴露出来的方法。

下面我们在看下.m里面的实现,这里多了一个类AFActivityIndicatorViewNotificationObserver,实现过程如下:

#import "UIActivityIndicatorView+AFNetworking.h"
#import <objc/runtime.h>

#if TARGET_OS_IOS || TARGET_OS_TV

#import "AFURLSessionManager.h"

@interface AFActivityIndicatorViewNotificationObserver : NSObject
@property (readonly, nonatomic, weak) UIActivityIndicatorView *activityIndicatorView;
- (instancetype)initWithActivityIndicatorView:(UIActivityIndicatorView *)activityIndicatorView;

- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task;

@end

@implementation UIActivityIndicatorView (AFNetworking)

- (AFActivityIndicatorViewNotificationObserver *)af_notificationObserver {
    AFActivityIndicatorViewNotificationObserver *notificationObserver = objc_getAssociatedObject(self, @selector(af_notificationObserver));
    if (notificationObserver == nil) {
        notificationObserver = [[AFActivityIndicatorViewNotificationObserver alloc] initWithActivityIndicatorView:self];
        objc_setAssociatedObject(self, @selector(af_notificationObserver), notificationObserver, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return notificationObserver;
}

- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task {
    [[self af_notificationObserver] setAnimatingWithStateOfTask:task];
}

@end

@implementation AFActivityIndicatorViewNotificationObserver

- (instancetype)initWithActivityIndicatorView:(UIActivityIndicatorView *)activityIndicatorView
{
    self = [super init];
    if (self) {
        _activityIndicatorView = activityIndicatorView;
    }
    return self;
}

- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task {
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];

    [notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil];
    [notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil];
    [notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil];
    
    if (task) {
        if (task.state != NSURLSessionTaskStateCompleted) {
            UIActivityIndicatorView *activityIndicatorView = self.activityIndicatorView;
            if (task.state == NSURLSessionTaskStateRunning) {
                [activityIndicatorView startAnimating];
            } else {
                [activityIndicatorView stopAnimating];
            }

            [notificationCenter addObserver:self selector:@selector(af_startAnimating) name:AFNetworkingTaskDidResumeNotification object:task];
            [notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingTaskDidCompleteNotification object:task];
            [notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingTaskDidSuspendNotification object:task];
        }
    }
}

#pragma mark -

- (void)af_startAnimating {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.activityIndicatorView startAnimating];
    });
}

- (void)af_stopAnimating {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.activityIndicatorView stopAnimating];
    });
}

#pragma mark -

- (void)dealloc {
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    
    [notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil];
    [notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil];
    [notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil];
}

@end

#endif

2. 接口方法的转发实现

接下里我们就从那个暴露出来的方法,来看这个分类的实现。

// AFActivityIndicatorViewNotificationObserver实例化,
// 并利用runtime绑定key对应的value
- (AFActivityIndicatorViewNotificationObserver *)af_notificationObserver {
    AFActivityIndicatorViewNotificationObserver *notificationObserver = objc_getAssociatedObject(self, @selector(af_notificationObserver));
    if (notificationObserver == nil) {
        notificationObserver = [[AFActivityIndicatorViewNotificationObserver alloc] initWithActivityIndicatorView:self];
        // 四个参数 object/key/value/policy
        objc_setAssociatedObject(self, @selector(af_notificationObserver), notificationObserver, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return notificationObserver;
}

- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task {
    // 调用了af_notificationObserver方法获取AFActivityIndicatorViewNotificationObserver的对象。
    [[self af_notificationObserver] setAnimatingWithStateOfTask:task];
}

这段代码主要做了下面几个工作:

  • 获取了AFActivityIndicatorViewNotificationObserver对象,并利用runtime绑定了key-value。
  • AFActivityIndicatorViewNotificationObserver对象的初始化。
  • 将接口那个方法转发到AFActivityIndicatorViewNotificationObserver中的方法了。

(a) AFActivityIndicatorViewNotificationObserver对象初始化

我们先看一下初始化

@property (readonly, nonatomic, weak) UIActivityIndicatorView *activityIndicatorView;

- (instancetype)initWithActivityIndicatorView:(UIActivityIndicatorView *)activityIndicatorView
{
    self = [super init];
    if (self) {
          // 只是简单的赋值
        _activityIndicatorView = activityIndicatorView;
    }
    return self;
}

这个初始化方法没什么特别的处理就是简单的赋值。

(b) 接口方法的转发

该分类的调用接口会转发到对象AFActivityIndicatorViewNotificationObserver中去实现。下面看一下是如何实现的。

- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task {
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];

    // 先移除对上个任务的通知监听
    [notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil];
    [notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil];
    [notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil];
    
    if (task) { 
        // 如果任务状态没有完成
        if (task.state != NSURLSessionTaskStateCompleted) {
            UIActivityIndicatorView *activityIndicatorView = self.activityIndicatorView;
            // 如果任务正在进行,就开始动画,否则就停止动画
            if (task.state == NSURLSessionTaskStateRunning) {
                [activityIndicatorView startAnimating];
            } else {
                [activityIndicatorView stopAnimating];
            }
            
            // 添加任务的开始暂停完成的通知
            [notificationCenter addObserver:self selector:@selector(af_startAnimating) name:AFNetworkingTaskDidResumeNotification object:task];
            [notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingTaskDidCompleteNotification object:task];
            [notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingTaskDidSuspendNotification object:task];
        }
    }
}

下面看一下这个方法的实现。

  • 首先移除对任务状态的监听,防止监听错误的任务到处出错。

  • 首先看一下任务的状态NSURLSessionTaskState,是一个枚举值,这个是苹果的API。

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);

如果任务没有完成,如果任务是在进行中,就开始动画,否则就停止动画。

  • 增加对任务开始、暂停和完成的通知监听。在通知方法的实现上就是在主线程进行开始或者停止动画。
- (void)af_startAnimating {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.activityIndicatorView startAnimating];
    });
}

- (void)af_stopAnimating {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.activityIndicatorView stopAnimating];
    });
}

最后在dealloc中移除对通知的监听。

后记

本篇主要是UIActivityIndicatorView的分类的一些动画的实现,将动画与任务的进度进行绑定。

相关文章

网友评论

    本文标题:AFNetworking源码探究(十九) —— UIKit相关之

    本文链接:https://www.haomeiwen.com/subject/rwutfftx.html