AFNetworking 3.0 源碼筆記 AFNetworkReachabilityManager

AFNetworkReachabilityManager 是AFNetworking框架里面 相對(duì)低耦合的一個(gè)部分,所以拿AFNetworkReachabilityManager開刀是個(gè)不錯(cuò)的算擇。

首先來看看AFNetworkReachability的功能:
'AFNetworkReachabilityManager' 監(jiān)視域名和WWAN和WiFi接口地址的Reachability。

然而網(wǎng)絡(luò)一般有兩種(蜂窩WWAN、WIFI)加上無網(wǎng)絡(luò)和未知錯(cuò)誤,一共四種網(wǎng)絡(luò)狀態(tài)
于是有了下面的枚舉類型:

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

通過這個(gè)需求我們引出了下面四個(gè)屬性:

/**
 當(dāng)前網(wǎng)絡(luò)可用性的狀態(tài)
 */
@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;

/**
 網(wǎng)絡(luò)當(dāng)前是否可用
 */
@property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;

/**
 WWAN網(wǎng)絡(luò)當(dāng)前是否可用
 */
@property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;

/**
 WiFI網(wǎng)絡(luò)當(dāng)前是否可用
 */
@property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;

*注:BOOL類型要給出getter方法以添加 is 或者 have 前綴。

接下來是初始化方法,對(duì)于這種全局監(jiān)控的類來說,單例肯定是必要的。

/**
 Returns the shared network reachability manager.
 */
+ (instancetype)sharedManager;

因?yàn)槲覀冞€要對(duì)特定的域名(domain)和網(wǎng)絡(luò)地址做監(jiān)控所以有了以下的初始化方法:

/**
 Creates and returns a network reachability manager for the specified domain.

 @param domain The domain used to evaluate network reachability.

 @return An initialized network reachability manager, actively monitoring the specified domain.
 */
+ (instancetype)managerForDomain:(NSString *)domain;

/**
 Creates and returns a network reachability manager for the socket address.

 @param address The socket address (`sockaddr_in6`) used to evaluate network reachability.

 @return An initialized network reachability manager, actively monitoring the specified socket address.
 */
+ (instancetype)managerForAddress:(const void *)address;

首先需要禁止用戶調(diào)用默認(rèn)的構(gòu)造方法init:

/**
 *  Initializes an instance of a network reachability manager
 *
 *  @return nil as this method is unavailable
 */
- (nullable instancetype)init NS_UNAVAILABLE;

然而如果有多種初始化方法就需要一個(gè)總的初始化方法,基本所有的初始化方法都應(yīng)該調(diào)用該總初始化方法。于是有了下面的初始化方法:

/**
 Initializes an instance of a network reachability manager from the specified reachability object.

 @param reachability The reachability object to monitor.

 @return An initialized network reachability manager, actively monitoring the specified reachability.
 */
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;

*注:NS_DESIGNATED_INITIALIZER表明該初始化方法是總初始化方法,所有的初始化方法(包括子類的)都應(yīng)該代用該方法。

就如同C++,應(yīng)該有一個(gè)默認(rèn)構(gòu)造于是有了下面的默認(rèn)構(gòu)造方法:

/**
 Creates and returns a network reachability manager with the default socket address.
 
 @return An initialized network reachability manager, actively monitoring the default socket address.
 */
+ (instancetype)manager;

網(wǎng)絡(luò)變化了,需要通過回調(diào)告訴用戶,一般傳值有如下方法:
1.代理 2.通知 3.block 4.KVO
KVO會(huì)添加用戶操作所以pass,通知用block替代以減少用戶操作。block是用于一對(duì)一的,當(dāng)你設(shè)置了新的block的時(shí)候上一個(gè)block會(huì)失效,然而通知?jiǎng)t不同他是一對(duì)多的。
關(guān)于block我們有了以下方法:

/**
 Sets a callback to be executed when the network availability of the `baseURL` host changes.

 @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`.
 */
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;

關(guān)于通知我們定義一下兩個(gè)NSString常量:一個(gè)用來表示通知的string,一個(gè)用來獲取通知userinfo中的信息

/**
 Posted when network reachability changes.
 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.

 @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`).
 */
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;

因?yàn)橐话闱闆r下是單例,無法銷毀,關(guān)閉監(jiān)聽的公開方法是必要的,既然有關(guān)閉監(jiān)聽的方法,開啟監(jiān)聽的方法也是必要的了。所以有了如下兩個(gè)方法:

/**
 Starts monitoring for changes in network reachability status.
 */
- (void)startMonitoring;

/**
 Stops monitoring for changes in network reachability status.
 */
- (void)stopMonitoring;

作為一個(gè)國(guó)際化的開發(fā)空間,反映出當(dāng)前網(wǎng)絡(luò)狀態(tài)的本地化文字也是必要的。所以有了如下方法:

/**
 Returns a localized string representation of the current network reachability status.
 */
- (NSString *)localizedNetworkReachabilityStatusString;

當(dāng)然也有個(gè)C方法是轉(zhuǎn)換當(dāng)前的AFNetworkReachabilityStatus到字符穿的

FOUNDATION_EXPORT NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);

之所以用C方法并且用了FOUNDATION_EXPORT關(guān)鍵字,我猜測(cè)是為了進(jìn)一步簡(jiǎn)化用戶操作。而且字符串檢測(cè)速度很快直接用"=="就可以了。

=================================== 我是分割線 ===================================

來看看如何實(shí)現(xiàn)這些方法:
首先這個(gè)類是通過蘋果的SCNetworkReachabilityRef來實(shí)現(xiàn)功能的,所以要有一個(gè)SCNetworkReachabilityRef的實(shí)例變量。這里我們定一個(gè)SCNetworkReachabilityRef類型的屬性:

@property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;

因?yàn)?h中networkReachabilityStatus是readonly,所以這里要把他變成readwrite

@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;

創(chuàng)建一個(gè)block,來存儲(chǔ)用戶的block

typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);
@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;

接下來實(shí)現(xiàn)總初始化方法:
想法很簡(jiǎn)答,把參數(shù)傳過來的SCNetworkReachabilityRef給保存到實(shí)例變量中,并且初始化networkReachabilityStatus的數(shù)值。

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

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

    return self;
}

*注:SCNetworkReachabilityRef是C層的結(jié)構(gòu)體指針,需要用CFRetain來持有。并且在不用的時(shí)候CFRelease釋放。

接下來實(shí)現(xiàn)另外兩個(gè)需要參數(shù)的工廠方法。這里所有的構(gòu)造方法最終都要調(diào)用總構(gòu)造,所以我們要把 domain 和 address 變成 SCNetworkReachabilityRef,然后傳遞給總構(gòu)造方法。
SCNetworkReachabilityRef 有三個(gè)構(gòu)造方法,這里用的是其中的兩個(gè)WithName 和 WithAddress。

+ (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;
}

*注:這里要CFRelease(reachability),因?yàn)樵诳倶?gòu)造方法中已經(jīng)CFRetain(reachability)了。

接下來實(shí)現(xiàn)的是默認(rèn)的工廠方法,看過《unix網(wǎng)絡(luò)編程》的人對(duì)這些代碼會(huì)比較熟悉。
首先需要一個(gè) sockaddr_in 的結(jié)構(gòu)體 來存儲(chǔ) socket 地址。
然后再用 bzero 把地址清空。
配置socket地址的基本屬性sin_family 和 sin_len。
當(dāng)然這里還需要根據(jù)系統(tǒng)來區(qū)分創(chuàng)建的是ipv6還是ipv4。
代碼如下:

+ (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)initWithReachability:(SCNetworkReachabilityRef)reachability {
    self = [super init];
    if (!self) {
        return nil;
    }

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

    return self;
}

最后來實(shí)現(xiàn)我們的單例方法,很簡(jiǎn)單的GCD調(diào)用:

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

    return _sharedManager;
}

當(dāng)然因?yàn)樾枰褂脩粽{(diào)用默認(rèn)的init方法所以做如下處理:

- (instancetype)init NS_UNAVAILABLE
{
    return nil;
}

先別急著寫別的,先把dealloc寫了,以免忘記(如果忘了可能會(huì)造成大麻煩?。?。
dealloc方法需要做兩件事:
1.將實(shí)例變量該release的release掉,這里指的就是networkReachabilityStatus。當(dāng)然在release之前需要判斷是否為空,如果已經(jīng)釋放完了,再釋放會(huì)崩潰的。
2.停止監(jiān)聽,調(diào)用自己的stopMonitoring方法就好。

- (void)dealloc {
    [self stopMonitoring];
    
    if (_networkReachability != NULL) {
        CFRelease(_networkReachability);
    }
}

然后實(shí)現(xiàn)咱們之前設(shè)置的三個(gè)表示網(wǎng)絡(luò)狀態(tài)的getter

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

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

- (BOOL)isReachableViaWiFi {
    return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi;
}

=================================== 我是分割線 ===================================
接下來就是重頭戲了startMonitoring。
這里挺復(fù)雜的我們先看源碼,一步一步來:

- (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);
        }
    });
}
[self stopMonitoring];

在任何需要開始之前,先調(diào)用停止的方法。以免重復(fù)棄用(socket連接,動(dòng)畫方法等 都是如此)。

if (!self.networkReachability) {
        return;
    }

容錯(cuò)機(jī)制

Boolean
SCNetworkReachabilitySetCallback        (
                        SCNetworkReachabilityRef            target,
                        SCNetworkReachabilityCallBack   __nullable  callout,
                        SCNetworkReachabilityContext    * __nullable    context
                        )               __OSX_AVAILABLE_STARTING(__MAC_10_3,__IPHONE_2_0);

這個(gè)是啟動(dòng)SCNetworkReachabilityRef
參數(shù)一 要啟動(dòng)的SCNetworkReachabilityRef
參數(shù)二 啟動(dòng)的 SCNetworkReachabilityRef變化的時(shí)候回調(diào)的SCNetworkReachabilityCallBack類型的函數(shù)指針
參數(shù)三 和參數(shù)二相相關(guān)的上下文

這里要講一下參數(shù)二
SCNetworkReachabilityCallBack 定義如下

typedef void (*SCNetworkReachabilityCallBack)   (
                        SCNetworkReachabilityRef            target,
                        SCNetworkReachabilityFlags          flags,
                        void                 *  __nullable  info
                        );

函數(shù)指針實(shí)際就是OC的block,大家完全可以把這個(gè)當(dāng)做一個(gè)block看待。我們像是定義一個(gè)block一樣來定義一個(gè)函數(shù)指針。

static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {

}

意思就是說當(dāng)
SCNetworkReachabilitySetCallback(::) 第一個(gè)參數(shù)啟動(dòng)的SCNetworkReachabilityRef發(fā)生變化的時(shí)候回直接調(diào)用這個(gè)函數(shù)。
這個(gè)函數(shù)中第一個(gè)參數(shù)(SCNetworkReachabilityRef __unused target)就是咱們啟動(dòng)的SCNetworkReachabilityRef。
第二個(gè)參數(shù)就是啟動(dòng)的SCNetworkReachabilityRef所變成的網(wǎng)絡(luò)狀態(tài),具體數(shù)值如下:

typedef CF_OPTIONS(uint32_t, SCNetworkReachabilityFlags) {
    kSCNetworkReachabilityFlagsTransientConnection  = 1<<0,
    kSCNetworkReachabilityFlagsReachable        = 1<<1,
    kSCNetworkReachabilityFlagsConnectionRequired   = 1<<2,
    kSCNetworkReachabilityFlagsConnectionOnTraffic  = 1<<3,
    kSCNetworkReachabilityFlagsInterventionRequired = 1<<4,
    kSCNetworkReachabilityFlagsConnectionOnDemand   = 1<<5, // __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_3_0)
    kSCNetworkReachabilityFlagsIsLocalAddress   = 1<<16,
    kSCNetworkReachabilityFlagsIsDirect     = 1<<17,
#if TARGET_OS_IPHONE
    kSCNetworkReachabilityFlagsIsWWAN       = 1<<18,
#endif  // TARGET_OS_IPHONE

    kSCNetworkReachabilityFlagsConnectionAutomatic  = kSCNetworkReachabilityFlagsConnectionOnTraffic
};

第三個(gè)參數(shù)就是咱們?cè)赟CNetworkReachabilitySetCallback中傳的第三個(gè)參數(shù)context中的一個(gè)info成員。

到這里

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

這行算是解釋完了。

但是我們還需要一個(gè)context,所以上面的

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

就是來創(chuàng)建這個(gè)的。

這個(gè)結(jié)構(gòu)體原型如下:

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;

第一個(gè)是版本號(hào)。
第二個(gè)是在SCNetworkReachabilitySetCallback(::)傳給第二個(gè)函數(shù)指針的第二個(gè)參數(shù)info成員。
第三個(gè) 對(duì)于info的retain操作的函數(shù)指針
第四個(gè) 對(duì)于info的release操作的函數(shù)指針
第五個(gè) 描述

這里第一個(gè)填0就好,最后一個(gè)填NULL就好,中間還差三個(gè)。

這里我們要?jiǎng)?chuàng)建一個(gè)info,這個(gè)info是要最后傳遞給我們之前創(chuàng)建的C函數(shù)

static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info)

中的。
而這個(gè)函數(shù)我們的目的是把第二個(gè)參數(shù)(網(wǎng)絡(luò)狀態(tài)),發(fā)送一個(gè)通知 并且 調(diào)用我們之前在.h中放出的

- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;

block回調(diào)。
但是問題來了! 這個(gè)是C函數(shù),沒有self.的操作!我們要調(diào)用之前的block不能用self.networkReachabilityStatusBlock來獲取這個(gè)block,這時(shí)候info就排上用場(chǎng)了!我們要把這個(gè)self.networkReachabilityStatusBlock來放到info的位置,把這個(gè)self.networkReachabilityStatusBlock傳過來就好了。

創(chuàng)建info

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

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

回到4.
第二個(gè)參數(shù)通過第6步我們就得到了(AFNetworkReachabilityStatusBlock callback)

后面兩個(gè)參數(shù),既然知道了info是block,所以也可以的出來了。

static const void * AFNetworkReachabilityRetainCallback(const void *info) {
    return Block_copy(info);
}
static void AFNetworkReachabilityReleaseCallback(const void *info) {
    if (info) {
        Block_release(info);
    }
}

再回到第4部,把第7部的兩個(gè)函數(shù)指針給到第3個(gè)和第4個(gè)參數(shù)里面,至此我們的context終于完成了。

然后回到第3步我們創(chuàng)建的C函數(shù)

static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {

}

這里第3個(gè)參數(shù)就是一個(gè)block了。

我們?cè)賱?chuàng)建一個(gè)C函數(shù)用來發(fā)送通知和回調(diào)block的。

/**
 * Queue a status change notification for the main thread.
 *
 * This is done to ensure that the notifications are received in the same order
 * as they are sent. If notifications are sent directly, it is possible that
 * a queued notification (for an earlier status condition) is processed after
 * the later update, resulting in the listener being left in the wrong state.
 */
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];
    });
}

然后調(diào)用這個(gè)函數(shù)

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

這里

 static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags)

是把系統(tǒng)的flag轉(zhuǎn)換成我們自己的AFNetworkReachabilityStatus
實(shí)現(xiàn)如下:

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

然后這里把這個(gè)放到Runloop中啟動(dòng)

SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);

最后我們?cè)倩氐介_始,因?yàn)榈谝淮斡脩糸_始startMonitoring的時(shí)候,self.networkReachability的變化是不會(huì)計(jì)算在內(nèi)的,所以不會(huì)產(chǎn)生通知 和 回調(diào)block,所以這里我們要手動(dòng)調(diào)用一次。

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

=================================== 我是分割線 ===================================

接下來就是收尾工作了:
stopMonitoring

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

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

本地化語言

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

KVO

#pragma mark - NSKeyValueObserving

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
    if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) {
        return [NSSet setWithObject:@"networkReachabilityStatus"];
    }

    return [super keyPathsForValuesAffectingValueForKey:key];
}

如果networkReachabilityStatus發(fā)生變化則reachable 、reachableViaWWAN 、reachableViaWiFi調(diào)用自己的getter方法。

完結(jié)散花。

寫在最后,如果大家喜歡幫忙點(diǎn)下“關(guān)注”和“喜歡”,大家的鼓勵(lì)是我最大的動(dòng)力。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容