ios-研究AFNetworking(1)-AFNetworkReachabilityManager类

本文详细解析了AFNetworking中AFNetworkReachabilityManager类的使用方法,包括如何通过不同方式创建网络连接引用,以及如何监测网络状态变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AFNetworking中提供了AFNetworkReachabilityManager类,用于应用生命周期中网络状态的监听。

AFNetworkReachabilityManager继承自NSObject

@interface AFNetworkReachabilityManager : NSObject


AFNetworkReachabilityManager定义了一个枚举,专门用来表示网络所处的各种状态

typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
    AFNetworkReachabilityStatusUnknown          = -1,
    AFNetworkReachabilityStatusNotReachable     = 0,
    AFNetworkReachabilityStatusReachableViaWWAN = 1,
    AFNetworkReachabilityStatusReachableViaWiFi = 2,
};
AFNetworkReachabilityStatusUnknown 表示未知网络

AFNetworkReachabilityStatusNotReachable 表示网络未连接

AFNetworkReachabilityStatusReachableViaWWAN 表示是手机网络,2G,3G,4G

AFNetworkReachabilityStatusReachableViaWiFi 表示连接的WiFi


@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
networkReachabilityStatus属性表示当前应用所处的网络状态


@property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
reachable 属性表示当前应用是否连接了网络,这个属性的getter方法被重新自定义过,如果应用处于手机网络(WWAN)或者WiFi状态下,就返回YES,否则返回NO,如下

- (BOOL)isReachable {
    return [self isReachableViaWWAN] || [self isReachableViaWiFi];
}


@property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;
reachableViaWWAN 属性表示应用当前是否处于WWAN网络状态下,如果在该网络环境下,就返回YES,否则返回NO


@property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;

reachableViaWiFi 属性表示应用当前是否处于WiFi网络状态下,如果应用处于WiFi环境下,就返回YES,否则返回NO

属性就讲到这里,消息我们就去.m文件中看看。

--------------------------------------------------------------------分割线,棒棒哒--------------------------------------------------------------------------------

@interface AFNetworkReachabilityManager ()
@property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;
@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
@end
SCNetworkReachabilityRef networkReachability; 属性

AFNetworkReachabilityStatus networkReachabilityStatus; 属性

AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock; 属性,这是一个block属性,用来做网络状态连接的时候,回调这个block


+ (instancetype)manager
{
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
    struct sockaddr_in6 address;
    bzero(&address, sizeof(address));
    address.sin6_len = sizeof(address);
    address.sin6_family = AF_INET6;
#else
    struct sockaddr_in address;
    bzero(&address, sizeof(address));
    address.sin_len = sizeof(address);
    address.sin_family = AF_INET;
#endif
    return [self managerForAddress:&address];
}
来分析下+(instancetype)manager类方法:

先预编译,根据__IPHONE_OS_VERSION_MIN_REQUIRED(ios版本号) 高于 9.0,以及__MAC_OS_X_VERSION_MIN_REQUIRED (mac版本号) 高于 10.11,那么我们就必须要使用ipv6的方式,如果低于这两个系统的版本号,我们就用ipv4的方法来创建socket套接字。


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

    CFRelease(reachability);
    
    return manager;
}
managerForAddress这个类方法是根据传入的套接字来创建一个网络连接引用。

SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault,(const struct sockaddr *)address);

这个c方法就是根据传入的参数来获取网络连接的一个引用,第一个参数可以是NULL或kCFAllocatorDefault,第二个参数就是需要测试连接的IP地址,创建好网络连接引用SCNetworkReachabilityRef使用后,注意要使用CFRelease来释放掉这个数据


上边提到用套接字作为一个网络连接引用创建的时候的参数,同样,我们可以不用套接字IP地址去做参数,我们可以提供一个域名来创建网络连接引用

+ (instancetype)managerForDomain:(NSString *)domain {
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);

    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;
}
一旦我们有了SCNetworkReachabilityRef网络连接的引用,那么我们就可以使用这个连接引用去初始化我们的属性_networkReachability,并且在初始化的时候我们先将 self.networkReachabilityStatus 设置为未知网络状态。


+ (instancetype)sharedManager {
    static AFNetworkReachabilityManager *_sharedManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedManager = [self manager];
    });

    return _sharedManager;
}
sharedManager方法就是使用manager来得到AFNetworkReachabilityManager单例


- (void)dealloc {
    [self stopMonitoring];
    
    if (_networkReachability != NULL) {
        CFRelease(_networkReachability);
    }
}
析构函数,里边的操作当然得释放资源了


- (BOOL)isReachable {
    return [self isReachableViaWWAN] || [self isReachableViaWiFi];
}

- (BOOL)isReachableViaWWAN {
    return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN;
}

- (BOOL)isReachableViaWiFi {
    return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi;
}
返回属性,已判断应用所处网络状态


- (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);
        }
    });
}
我们来重点看看这个方法实现:

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

        strongSelf.networkReachabilityStatus = status;
        if (strongSelf.networkReachabilityStatusBlock) {
            strongSelf.networkReachabilityStatusBlock(status);
        }

    };
这里我们创建了一个AFNetworkReachabilityStatusBlock类型的block,在这个block里边我们执行了我们的属性block,也就是说,一旦回调callback这个block,那么相应的我们自定义的AFNetworkReachabilityStatusBlock的属性_networkReachabilityStatusBlock也会被回调。

SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
创建SCNetworkReachabilityContext context,介绍下SCNetworkReachabilityContext结构内容

typedef struct {
      CFIndex version;
      void * info;
      const void *(*retain)(const void *info);
      void (*release)(const void *info);
      CFStringRef (*copyDescription)(const void *info);
} SCNetworkReachabilityContext;
这个结构体中涉及到的几个参数

CFIndex version; 0 

void * info; 就是上边创建的callback

const void * (*retain)(const void * info); 返回任意指针类型,参数是一个指针,的指针函数

static const void * AFNetworkReachabilityRetainCallback(const void *info) {
    return Block_copy(info);
}
void (*release)(const void * info);

static void AFNetworkReachabilityReleaseCallback(const void *info) {
    if (info) {
        Block_release(info);
    }
}
CFStringRef (*copyDescription) (const void *info); NULL


SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);

试着给self.networkReachability这个网络连接引用设置回调方法,如果self.networkReachability这个网络连接引用发生改变,那么AFNetworkReachabilityCallBack就会回调

static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
    AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
}
一旦self.networkReachability发生改变,上边的方法就会被调用,所以AFPostReachabilityStatusChange();方法就会被调用

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];
    });
}
然后根据flags得到网络连接状态AFNetworkReachabilityStatus

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;
}
然后异步执行callback回调方法,自然的我们自定义的block属性也被调用了,上边解释过了

最后发送AFNetworkingReachabilityDidChangeNotification通知,这个通知携带了网络状态情况


SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
这句代码就是将网络连接引用状态的变化监听放入MainRunLoop中,为了在应用整个生命周期中,都能够得到检测和响应。


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

Boolean SCNetworkReachabilityGetFlags (
   SCNetworkReachabilityRef target,
   SCNetworkReachabilityFlags *flags
);
这个函数用来获得测试连接的状态,第一个参数为之前建立的测试连接的引用,第二个参数用来保存获得的状态,如果能获得状态则返回TRUE,否则返回FALSE

先异步执行一个网络连接引用状态是否改变的监听


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

    SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
停止网络连接引用状态的监听,从MainRunLoop中删除掉


- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
    self.networkReachabilityStatusBlock = block;
}
自定义我们的block内容,给self.networkReachabilityStatusBlock赋予我们想要的操作,以至于满足项目需求


关于AFNetworkReachabilityManager的分析就讲到这里,以后遇到实际应用,再回来补充实际使用情况......

















































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值