AFN3.2第1篇-AFNetworkReachabilityManager

AFNetworkReachabilityManager目录

AFNetworkReachabilityManager概述

AFNetworkReachabilityManager是AFN封装了系统的SystemConfiguration的API做出的关于网络状态监测的类。

AFN提供的网络状态枚举如下:

typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
    AFNetworkReachabilityStatusUnknown          = -1,   //未知状态
    AFNetworkReachabilityStatusNotReachable     = 0,    //不可达
    AFNetworkReachabilityStatusReachableViaWWAN = 1,    //蜂窝数据
    AFNetworkReachabilityStatusReachableViaWiFi = 2,    //WiFi
};

我们不能根据不可达这种状态就放弃发送网络请求,正如AFN本身所述:
Reachability can be used to determine background information about why a network operation failed, or to trigger a network operation retrying when a connection is established. It should not be used to prevent a user from initiating a network request, as it’s possible that an initial request may be required to establish reachability. (网络状态不可以用来阻止用户发起请求,因为有可能这个请求就是用来判断网络状态的)

AFNetworkReachabilityManager.h

网络状态描述

AFNetworkReachabilityStatus networkReachabilityStatus; 
BOOL reachable;
BOOL reachableViaWWAN;
BOOL reachableViaWiFi;

初始化方法

+ (instancetype)sharedManager;
+ (instancetype)manager;
//只针对一个domain监控
+ (instancetype)managerForDomain:(NSString *)domain;
+ (instancetype)managerForAddress:(const void *)address;
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;

设置与监听

//必须调用这个方法才能有网络状态变化的通知与回调
- (void)startMonitoring;
- (void)stopMonitoring;
- (NSString *)localizedNetworkReachabilityStatusString;

//网络发生变化时Block回调
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;

AFNetworkReachabilityManager.m

AFN封装的本地化网络状态描述

NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) {
    switch (status) {
        case AFNetworkReachabilityStatusNotReachable:
            return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil);
        case AFNetworkReachabilityStatusReachableViaWWAN:
            return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil);
        case AFNetworkReachabilityStatusReachableViaWiFi:
            return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil);
        case AFNetworkReachabilityStatusUnknown:
        default:
            return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil);
    }
}

- (NSString *)localizedNetworkReachabilityStatusString {
    return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus);
}

判断网络状态

static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {
    //网络可达
    BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
    //需要连接
    BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
    //可以自动连接
    BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0));
    //无需用户操作即可连接
    BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0);

    BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction));

    AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown;
    if (isNetworkReachable == NO) {
        status = AFNetworkReachabilityStatusNotReachable;
    }
#if    TARGET_OS_IPHONE
    else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) {
        status = AFNetworkReachabilityStatusReachableViaWWAN;
    }
#endif
    else {
        status = AFNetworkReachabilityStatusReachableViaWiFi;
    }

    return status;
}

状态变化通知

static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
    AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);

    //主线程发送网络状态通知
    dispatch_async(dispatch_get_main_queue(), ^{
        //首先进行Block回调操作
        if (block) {
            block(status);
        }
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
        [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
    });
}

static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
    AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
}

//这里如果设置了会在出现网络状态变化的时候回调
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
    self.networkReachabilityStatusBlock = block;
}

监测和停止监测

- (void)startMonitoring {
    [self stopMonitoring];

    if (!self.networkReachability) {
        return;
    }

    __weak __typeof(self)weakSelf = self;
    AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;

        //状态记录变更
        strongSelf.networkReachabilityStatus = status;

        //用户设置的Block回调
        if (strongSelf.networkReachabilityStatusBlock) {
            strongSelf.networkReachabilityStatusBlock(status);
        }

    };

    /*  新建上下文: user-specified data and callbacks for SCNetworkReachability.
    typedef struct {
        CFIndex        version;
        void *        __nullable info;
        const void    * __nonnull (* __nullable retain)(const void *info);
        void        (* __nullable release)(const void *info);
        CFStringRef    __nonnull (* __nullable copyDescription)(const void *info);
    } SCNetworkReachabilityContext;
     */
    SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};

    /* 设置回调: Assigns a client to a target, which receives callbacks when the reachability of the target changes.
    Boolean SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target,
                                             SCNetworkReachabilityCallBack __nullable callout,
                                             SCNetworkReachabilityContext * __nullable context);
    */
    SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);

    //加入RunLoop:  Schedules the given target with the given run loop and mode.
    SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);

    //异步线程 发送一次当前的网络状态
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
        SCNetworkReachabilityFlags flags;

        //SCNetworkReachabilityGetFlags: Determines if the given target is reachable using the current network configuration.
        if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
            AFPostReachabilityStatusChange(flags, callback);
        }
    });
}

- (void)stopMonitoring {
    if (!self.networkReachability) {
        return;
    }

    SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}

AFNetworkReachabilityManager总结

AFNetworkReachabilityManager实际上对系统库进行了封装,提供了简洁方便的用法和API。AFNetworkReachabilityManager的主要方法在于startMonitoring以及之后的状态通知,至于具体怎么判断网络状态是另一个话题。

  • 关于回调
// Assigns a client to a target, which receives callbacks when the reachability of the target changes.
Boolean SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target,
                                             SCNetworkReachabilityCallBack __nullable callout,
                                             SCNetworkReachabilityContext * __nullable context);
  • AFNetworkReachabilityCallback
    上面的方法传入的这个Block实际是在接受系统回调和发送通知。
    AFPostReachabilityStatusChange中实现了获取真实状态,callback修改networkReachabilityStatus属性,并在主线程发送网络状态变化的通知。

  • setReachabilityStatusChangeBlock
    用户如果自己设置了回调的Block则会在callback这个Block中回调当前的状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值