AFNetworking源码阅读(二)AFNetworkReachabilityManager

 

 AFNetworkReachabilityManager.h

1 #if !TARGET_OS_WATCH
2 ...
3 #endif

  表示当前只适用于 非 WATCH 平台开发。

1 #import <SystemConfiguration/SystemConfiguration.h>

   主要依赖 SystemConfiguration 框架来进行网络可达性监测。

1 typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
2     AFNetworkReachabilityStatusUnknown          = -1,
3     AFNetworkReachabilityStatusNotReachable     = 0,
4     AFNetworkReachabilityStatusReachableViaWWAN = 1,
5     AFNetworkReachabilityStatusReachableViaWiFi = 2,
6 };

  表示网络可达性的一个枚举,有4个值,从上到下分别表示:未知、无网络连接、蜂窝数据、WI-FI。

 属性

 1 @interface AFNetworkReachabilityManager : NSObject
 2 
 3 /**
 4  The current network reachability status.
 5  */
 6 @property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
 7 
 8 /**
 9  Whether or not the network is currently reachable.
10  */
11 @property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
12 
13 /**
14  Whether or not the network is currently reachable via WWAN.
15  */
16 @property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;
17 
18 /**
19  Whether or not the network is currently reachable via WiFi.
20  */
21 @property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;

  networkReachabilityStatus 表示当前的可达性状态,只读的 AFNetworkReachabilityStatus 枚举值。

  reachable 表示当前网络是否可达,只读布尔类型。

  reachableViaWWAN 表示当前的蜂窝数据网络是否可用,只读布尔类型。

  reachableViaWiFi 表示当前的 Wi-Fi 网络是否可用,只读布尔类型。

 方法

 1 /**
 2  Returns the shared network reachability manager.
 3  */
 4 + (instancetype)sharedManager;
 5 
 6 /**
 7  Creates and returns a network reachability manager with the default socket address.
 8  
 9  @return An initialized network reachability manager, actively monitoring the default socket address.
10  */
11 + (instancetype)manager;
12 
13 /**
14  Creates and returns a network reachability manager for the specified domain.
15 
16  @param domain The domain used to evaluate network reachability.
17 
18  @return An initialized network reachability manager, actively monitoring the specified domain.
19  */
20 + (instancetype)managerForDomain:(NSString *)domain;
21 
22 /**
23  Creates and returns a network reachability manager for the socket address.
24 
25  @param address The socket address (`sockaddr_in6`) used to evaluate network reachability.
26 
27  @return An initialized network reachability manager, actively monitoring the specified socket address.
28  */
29 + (instancetype)managerForAddress:(const void *)address;
30 
31 /**
32  Initializes an instance of a network reachability manager from the specified reachability object.
33 
34  @param reachability The reachability object to monitor.
35 
36  @return An initialized network reachability manager, actively monitoring the specified reachability.
37  */
38 - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
39 
40 ///--------------------------------------------------
41 /// @name Starting & Stopping Reachability Monitoring
42 ///--------------------------------------------------
43 
44 /**
45  Starts monitoring for changes in network reachability status.
46  */
47 - (void)startMonitoring;
48 
49 /**
50  Stops monitoring for changes in network reachability status.
51  */
52 - (void)stopMonitoring;
53 
54 ///-------------------------------------------------
55 /// @name Getting Localized Reachability Description
56 ///-------------------------------------------------
57 
58 /**
59  Returns a localized string representation of the current network reachability status.
60  */
61 - (NSString *)localizedNetworkReachabilityStatusString;
62 
63 ///---------------------------------------------------
64 /// @name Setting Network Reachability Change Callback
65 ///---------------------------------------------------
66 
67 /**
68  Sets a callback to be executed when the network availability of the `baseURL` host changes.
69 
70  @param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`.
71  */
72 - (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;

  + (instancetype)sharedManager; 返回 AFNetworkReachabilityManager 的单例对象。

  + (instancetype)manager; 创建并返回具有默认 socket 地址的 AFNetworkReachabilityManager 对象,主动监视默认的 socket 地址。

  + (instancetype)managerForDomain:(NSString *)domain; 创建并返回指定域的 AFNetworkReachabilityManager 对象,主动监视指定域的网络状态。

  + (instancetype)managerForAddress:(const void *)address; 创建并返回指定 socket 地址的 AFNetworkReachabilityManager 对象,主动监视指定的 socket 地址。

  + (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER; 创建并返回一个用指定的 SCNetworkReachabilityRef 对象初始化的 AFNetworkReachabilityManager 对象,主动监视指定的可达性。

  // 开始和结束网络可达性监测

  - (void)startMonitoring; 开始监视网络可达性状态的变化。

  - (void)stopMonitoring; 停止监视网络可达性状态的变化。

  // 获得局部性网络可达性描述

  - (NSString *)localizedNetworkReachabilityStatusString; 返回当前网络可达状态的本地化字符串表示形式。往往可以根据这个字符串来告诉用户,当前网络发生了什么,当然,也可以根据状态自定义提示文字。

  // 设置网络可达性状态变化回调

  - (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block; 设置一个回调,当网络可达性状态变化的时候会执行。该 block 携带一个 AFNetworkReachabilityStatus 参数执行。

  设置网络转态改变的回调,监听网络改变的回调有两种方式:

  1.使用上边的这个 block 。

  2.监听 AFNetworkingReachabilityDidChangeNotification 通知。

 通知名字

1 /**
2  Posted when network reachability changes.
3  This notification assigns no notification object. The `userInfo` dictionary contains an `NSNumber` object under the `AFNetworkingReachabilityNotificationStatusItem` key, representing the `AFNetworkReachabilityStatus` value for the current network reachability.
4 
5  @warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import <SystemConfiguration/SystemConfiguration.h>` to the header prefix of the project (`Prefix.pch`).
6  */
7 FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;
8 FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;

  AFNetworkingReachabilityDidChangeNotification 当网络可达性改变的时候发送的通知。通知的内容里面含有一个 AFNetworkReachabilityStatus 枚举值表示当前的网络状态。

  这个是与网络状态变化相关的通知。接受的通知中会有一个 userinfo 是一个 NSDictionary 其中 key 就是 AFNetworkingReachabilityNotificationStatusItem 

  这简单的两行代码能够告诉我们的是,我们平时的开发中 但凡设计到发通知的功能,我们应该把通知的字符串封装到一个专有的文件中,同时在文件内部按不同模块进行区分,当然必要的注释也很有必要。

  ps: FOUNDATION_EXPORT 和 #define 都能定义常量。FOUNDATION_EXPORT 能够使用 == 进行判断,效率略高。而且能够隐藏定义细节(就是实现部分不在 .h 中)。

  AFNetworkingReachabilityNotificationStatusItem 为了检测网络的可达性

1 /**
2  Returns a localized string representation of an `AFNetworkReachabilityStatus` value.
3  */
4 FOUNDATION_EXPORT NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);

  定义一个 C 语言函数,参数只要一个 AFNetworkReachabilityStatus 返回一个本地化的字符串表示一个 AFNetworkReachabilityStatus 的枚举值。

 AFNetworkReachabilityManager.m

1 NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";
2 NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";

  给 .h 里面的两个通知的名字赋值。

1 typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);

  定义一个参数只有一个 AFNetworkReachabilityStatus 的名字是 AFNetworkReachabilityStatusBlock 的 block。

 1 NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) {
 2     switch (status) {
 3         case AFNetworkReachabilityStatusNotReachable:
 4             return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil);
 5         case AFNetworkReachabilityStatusReachableViaWWAN:
 6             return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil);
 7         case AFNetworkReachabilityStatusReachableViaWiFi:
 8             return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil);
 9         case AFNetworkReachabilityStatusUnknown:
10         default:
11             return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil);
12     }
13 }
1 #define NSLocalizedStringFromTable(key, tbl, comment) \
2         [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:(tbl)]

  这里的 tbl 表示自定定义的 .strings 文件的名字,默认是:Localizable.strings 的时候本地化字符串就使用:

1 #define NSLocalizedString(key, comment) \
2         [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil]

  这里的则多了一个 tbl 参数,它在代码中的固定值是: @"AFNetworking"。

 1 static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {
  // 是否能够到达
2 BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
  // 在联网之前需要建立连接
3 BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
  // 是否可以自动连接
4 BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0));
  // 是否可以连接,在不需要用户手动设置的前提下
5 BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0);
  // 是否可以联网的条件:1.能够到达 2.不需要建立连接或者不需要用户手动设置连接 就表示能够连接网络
6 BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction)); 7 8 AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown; 9 if (isNetworkReachable == NO) { 10 status = AFNetworkReachabilityStatusNotReachable; 11 } 12 #if TARGET_OS_IPHONE 13 else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { 14 status = AFNetworkReachabilityStatusReachableViaWWAN; 15 } 16 #endif 17 else { 18 status = AFNetworkReachabilityStatusReachableViaWiFi; 19 } 20 21 return status; 22 }
 1 typedef CF_OPTIONS(uint32_t, SCNetworkReachabilityFlags) {
 2     kSCNetworkReachabilityFlagsTransientConnection    = 1<<0,
 3     kSCNetworkReachabilityFlagsReachable        = 1<<1,
 4     kSCNetworkReachabilityFlagsConnectionRequired    = 1<<2,
 5     kSCNetworkReachabilityFlagsConnectionOnTraffic    = 1<<3,
 6     kSCNetworkReachabilityFlagsInterventionRequired    = 1<<4,
 7     kSCNetworkReachabilityFlagsConnectionOnDemand    = 1<<5,    // __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_3_0)
 8     kSCNetworkReachabilityFlagsIsLocalAddress    = 1<<16,
 9     kSCNetworkReachabilityFlagsIsDirect        = 1<<17,
10 #if    TARGET_OS_IPHONE
11     kSCNetworkReachabilityFlagsIsWWAN        = 1<<18,
12 #endif    // TARGET_OS_IPHONE
13 
14     kSCNetworkReachabilityFlagsConnectionAutomatic    = kSCNetworkReachabilityFlagsConnectionOnTraffic
15 };

  这是 SystemConfiguration 框架里面 SCNetworkReachability.h 文件定义的一个名字为 SCNetworkReachabilityFlags 的宏。

  比较常用的是:

  kSCNetworkReachabilityFlagsReachable 表示能够连接网络

  kSCNetworkReachabilityFlagsConnectionRequired 表示能够连接网络,但是首先得建立连接过程。

  kSCNetworkReachabilityFlagsIsWWAN 表示判断是否通过蜂窝网覆盖的连接,比如EDGE,GPRS,3G,4G,主要用来区分通过 Wi-Fi 的连接。

 

  该方法把传进来的 SCNetworkReachabilityFlags 与各个枚举值做 与 操作,最后返回一个 AFNetworkReachabilityStatus 的枚举值。即根据 SCNetworkReachabilityFlags 这个网络标记来转换成我们在开发中经常使用的网络状态。

  很多框架中都会把一个类中的私有方法写成这样。为什么呢? 在开发中经常会写成 - (void)funcName;  这样的私有方法。

  一个类中的私有方法可写成 static void funcName() 这样的 c 函数比较好。 

  1. 在文件的最前方,比较容易查找

  2. 可以适当的使用内联函数,提高效率。

 1 /**
 2  * Queue a status change notification for the main thread.
 3  *
 4  * This is done to ensure that the notifications are received in the same order
 5  * as they are sent. If notifications are sent directly, it is possible that
 6  * a queued notification (for an earlier status condition) is processed after
 7  * the later update, resulting in the listener being left in the wrong state.
 8  */
 9 static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
10     AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
11     dispatch_async(dispatch_get_main_queue(), ^{
12         if (block) {
13             block(status);
14         }
15         NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
16         NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
17         [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
18     });
19 }

  当网络可达性改变的时候,根据传入的指定的 SCNetworkReachabilityFlags 获得当前的网络可达性状态。

  并在主线程执行网络状态改变的 block 回调和携带当前的网络可达性状态发送名字是 AFNetworkingReachabilityDidChangeNotification 的通知。

  保证两种方式的数据统一,把它们封在了同一个函数里面。

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

   这个方法的内部实现是调用上面的那个方法,传入的 target 参数也没有使用。

1 static const void * AFNetworkReachabilityRetainCallback(const void *info) {
2     return Block_copy(info);
3 }
4 
5 #define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))

  使回调的 block 保持拥有,不被释放。

  Block_copy 可以把 block 放到堆中。

1 static void AFNetworkReachabilityReleaseCallback(const void *info) {
2     if (info) {
3         Block_release(info);
4     }
5 }
1 #define Block_release(...) _Block_release((const void *)(__VA_ARGS__))

  和上面相反用于释放 block。

  由于block也是 NSObject,可以对其进行 retain 操作。不过在将 block 作为回调函数传递给底层框架时,底层框架需要对其 copy 一份。比方说,如果将回调 block 作为属性,不能用 retain,而要用 copy。通常会将 block 写在栈中,而需要回调时,往往回调 block 已经不在栈中了,使用 copy 属性可以将 block 放到堆中。或者使用 Block_copy() 和 Block_release()。

1 @interface AFNetworkReachabilityManager ()
2 @property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;
3 @property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
4 @property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
5 @end
1 typedef const struct CF_BRIDGED_TYPE(id) __SCNetworkReachability * SCNetworkReachabilityRef;

  定义了三个属性。第一个属性是一个不可变的结构体。

  第二和第三个是纪录网络可达性状态的枚举值和只有一个网络可达性枚举值做参数的 block。

1 + (instancetype)sharedManager {
2     static AFNetworkReachabilityManager *_sharedManager = nil;
3     static dispatch_once_t onceToken;
4     dispatch_once(&onceToken, ^{
5         _sharedManager = [self manager];
6     });
7 
8     return _sharedManager;
9 }

  创建 AFNetworkReachabilityManager 的单例对象。

 1 + (instancetype)manager
 2 {
 3 #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)
 4     struct sockaddr_in6 address;
 5     bzero(&address, sizeof(address));
 6     address.sin6_len = sizeof(address);
 7     address.sin6_family = AF_INET6;
 8 #else
 9     struct sockaddr_in address;
10     bzero(&address, sizeof(address));
11     address.sin_len = sizeof(address);
12     address.sin_family = AF_INET;
13 #endif
14     return [self managerForAddress:&address];
15 }
1 void     bzero(void *, size_t) __POSIX_C_DEPRECATED(200112L);

  由于 IPv6 是 iOS 9 和 os_x 10.11 后边推出的,所有要进行版本判断。这里面涉及到 socket 的知识。

通过这段代码我们能学到什么呢?

  1. 方法的创建也是有顺序的,可以使用函数访问函数的思想。

  2. @if 这样的预编译指令能够替换掉代码中部分 if else 。好处就是代码会不会被编译的区别。

  bzero 置字节字符串前 n 个字节为零且包括 '\0'。

1 #define    AF_INET        2        /* internetwork: UDP, TCP, etc. */
1 + (instancetype)managerForAddress:(const void *)address {
2     SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
3     AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
4 
5     CFRelease(reachability);
6     
7     return manager;
8 }
1 + (instancetype)managerForDomain:(NSString *)domain {
2     SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
3 
4     AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
5     
6     CFRelease(reachability);
7 
8     return manager;
9 }

  这两个方法都是创建一个 AFNetworkReachabilityManager 。区别是用两种不同的方式创建一个 SCNetworkReachabilityRef 对象。

  方法1: 通过一个 socket 地址来初始化。 首先新建 SCNetworkReachabilityRef 对象,然后调用initWithReachability: 方法。记得手动管理内存。

  方法2: 通过一个指定 domain 来初始化。

  

  综合上边两个方法,我们发现 SCNetworkReachabilityRef 有两个创建方法:

  1. SCNetworkReachabilityCreateWithName 

  2. SCNetworkReachabilityCreateWithAddress

  

 1 - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
 2     self = [super init];
 3     if (!self) {
 4         return nil;
 5     }
 6 
 7     _networkReachability = CFRetain(reachability);
 8     self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
 9 
10     return self;
11 }

  并把 reachability 赋给属性 _networkReachability。CFRetain() 后要记得 CFRelease()。

 1 - (instancetype)init NS_UNAVAILABLE
 2 {
 3     return nil;
 4 }
 5 
 6 - (void)dealloc {
 7     [self stopMonitoring];
 8     
 9     if (_networkReachability != NULL) {
10         CFRelease(_networkReachability);
11     }
12 }

  dealloc 的时候 stopMonitoring,并释放 _networkReachability。

 1 - (BOOL)isReachable {
 2     return [self isReachableViaWWAN] || [self isReachableViaWiFi];
 3 }
 4 
 5 - (BOOL)isReachableViaWWAN {
 6     return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN;
 7 }
 8 
 9 - (BOOL)isReachableViaWiFi {
10     return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi;
11 }
 1 - (void)startMonitoring {
 2     [self stopMonitoring];
 3 
 4     if (!self.networkReachability) {
 5         return;
 6     }
 7 
 8     __weak __typeof(self)weakSelf = self;
 9     AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
10         __strong __typeof(weakSelf)strongSelf = weakSelf;
11 
12         strongSelf.networkReachabilityStatus = status;
13         if (strongSelf.networkReachabilityStatusBlock) {
14             strongSelf.networkReachabilityStatusBlock(status);
15         }
16 
17     };
18 
19     SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
20     SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
21     SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
22 
23     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
24         SCNetworkReachabilityFlags flags;
25         if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
26             AFPostReachabilityStatusChange(flags, callback);
27         }
28     });
29 }

  开始监视。

1 typedef struct {
2     CFIndex        version;
3     void *        __nullable info;
4     const void    * __nonnull (* __nullable retain)(const void *info);
5     void        (* __nullable release)(const void *info);
6     CFStringRef    __nonnull (* __nullable copyDescription)(const void *info);
7 } SCNetworkReachabilityContext;

  SCNetworkReachabilityContext 这是一个结构体,一般 C 语言的结构体是对要保存的数据的一种描述。

1 typedef signed long CFIndex;

  1.第一个参数接收一个 signed long 的参数。

  2.第二个参数接收一个 void * 类型的值,相当于 OC 的 id 类型,void * 可以指向任何类型的参数。

  3.第三个参数 是一个函数,目的是对 info 做 retain 操作,

  4.第四个参数是一个函数,目的是对 info 做 release 操作

  5.第五个参数是 一个函数,根据 info 获取 Description 字符串

  携带的 info 就是这个 block:

 1     __weak __typeof(self)weakSelf = self;
 2     AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
 3         __strong __typeof(weakSelf)strongSelf = weakSelf;
 4 
 5         strongSelf.networkReachabilityStatus = status;
 6         if (strongSelf.networkReachabilityStatusBlock) {
 7             strongSelf.networkReachabilityStatusBlock(status);
 8         }
 9 
10     };

  rerain 和 release 就是这两个函数:

1 static const void * AFNetworkReachabilityRetainCallback(const void *info) {
2     return Block_copy(info);
3 }
4 
5 static void AFNetworkReachabilityReleaseCallback(const void *info) {
6     if (info) {
7         Block_release(info);
8     }
9 }

  设置网络监听的步骤:

  1.先创建上下文:

1     SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};

  2.设置回调

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

  AFNetworkReachabilityCallback:

1 typedef void (*SCNetworkReachabilityCallBack)    (
2                         SCNetworkReachabilityRef            target,
3                         SCNetworkReachabilityFlags            flags,
4                         void                 *    __nullable    info
5                         );
1 SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);

  加入 RunLoop 池。KCFRunLoopCommonModes 表示主 RunLoop。

  在异步线程,发送一次当前的网络状态。

1 - (void)stopMonitoring {
2     if (!self.networkReachability) {
3         return;
4     }
5 
6     SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
7 }

  停止网络监视。

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

  本地化网络状态字符串。

1 - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
2     self.networkReachabilityStatusBlock = block;
3 }
1 + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
2     if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) {
3         return [NSSet setWithObject:@"networkReachabilityStatus"];
4     }
5 
6     return [super keyPathsForValuesAffectingValueForKey:key];
7 }

  注册键值依赖。

END

参考链接:http://blog.csdn.net/playddt/article/details/46332547

 http://blog.csdn.net/zhibudefeng/article/details/7631230

http://www.cnblogs.com/machao/p/5681645.html

posted @ 2017-06-21 05:31  鳄鱼不怕牙医不怕  阅读(1318)  评论(0编辑  收藏  举报