AFNetworkReachabilityManager

AFNetworkReachabilityManager的使用

初始化 AFNetworkReachabilityManager

在初始化方法中使用SCNetworkReachabilityCreateWithAddress或者SCNetworkReachabilityCreateWithName生成一个SCNetworkReachabilityRef的引用

+ (instancetype)managerForDomain:(NSString *)domain {
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
    AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
    CFRelease(reachability);
    return manager;
}

+ (instancetype)managerForAddress:(const void *)address {
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
    AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
    CFRelease(reachability);
    return manager;
}

- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
    self = [super init];
    if (!self) {
        return nil;
    }

    _networkReachability = CFRetain(reachability);
    self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;

    return self;
}
  1. 这两个方法通过 域名 或者有个 sockaddr_in指针 生成了一个SCNetworkReachabilityRef
  2. 调用- [AFNetworkReachabilityManager initWithReachability:]将生成的SCNetworkReachabilityRef传入
  3. 设置默认networkReachabilityStatus

监控网络状态

在初始化了manager之后,我们需要调用startMonitoring来开始监控网络状态

- (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;
        if (strongSelf.networkReachabilityStatusBlock) {
            strongSelf.networkReachabilityStatusBlock(status);
        }

    };

    SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
    SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
    SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
        SCNetworkReachabilityFlags flags;
        if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
            AFPostReachabilityStatusChange(flags, callback);
        }
    });
}

在该方法中创建了每次网络状态改变时的回调AFNetworkReachabilityStatusBlock,当回调发生时,重新设置status属性,调用设置的networkReachabilityStatusBlock属性

监控网络状态核心代码

  1. 创建一个SCNetworkReachabilityContext

    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
    };
  2. 当目标状态改变时 调用传入的回调

    SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
    static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
    AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
    }
    static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
    AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
    dispatch_async(dispatch_get_main_queue(), ^{
    if (block) {
    block(status);
    }
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
    [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
    });
    }
    1. 当网络状态改变时 会将context作为参数 回调AFNetworkReachabilityCallback
    2. AFNetworkReachabilityCallback中,将context中的block,以及作为状态的flags作为参数调用了 AFPostReachabilityStatusChange状态改变方法
    3. 利用AFNetworkReachabilityStatusForFlags函数将flags转变为网络状态status
    4. 在主线程中执行block(status) 并发送状态改变的通知
  3. 在MainRunLoop中监控网络状态

    SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
    
  4. 获取当前网络状态 调用callback

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
        SCNetworkReachabilityFlags flags;
    if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
    AFPostReachabilityStatusChange(flags, callback);
    }
    });