這個(gè)文件是監(jiān)聽(tīng)網(wǎng)絡(luò)狀態(tài)的底桂,里面東西很簡(jiǎn)單湖苞,弄懂那幾個(gè)結(jié)構(gòu)體就行了,就不多說(shuō)了碉熄,直接上代碼桨武。
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
//未知狀態(tài)
AFNetworkReachabilityStatusUnknown = -1,
//無(wú)網(wǎng)絡(luò)
AFNetworkReachabilityStatusNotReachable = 0,
//蜂窩移動(dòng)網(wǎng)絡(luò)
AFNetworkReachabilityStatusReachableViaWWAN = 1,
//WiFi
AFNetworkReachabilityStatusReachableViaWiFi = 2,
};
作者把SCNetworkReachabilityFlags
里的狀態(tài)簡(jiǎn)單的封裝成了常用的這四種,夠大多數(shù)情況下的使用了锈津。
/**
當(dāng)前網(wǎng)絡(luò)狀態(tài)
*/
@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
/**
網(wǎng)絡(luò)是否可用
*/
@property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
/**
是否是蜂窩移動(dòng)網(wǎng)絡(luò)
*/
@property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;
/**
是否是wifi
*/
@property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;
作者暴露了這四個(gè)屬性供我們獲取當(dāng)前的網(wǎng)絡(luò)環(huán)境呀酸。
#pragma mark 初始化方法:
/**
單例初始化
*/
+ (instancetype)sharedManager;
/**
默認(rèn)socket地址的初始化
*/
+ (instancetype)manager;
/**
根據(jù)給定的域名初始化
*/
+ (instancetype)managerForDomain:(NSString *)domain;
/**
根據(jù)給定的socket地址初始化
*/
+ (instancetype)managerForAddress:(const void *)address;
/**
根據(jù)給定的可到達(dá)對(duì)象初始化
*/
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
需要對(duì)一個(gè)socket地址或者一個(gè)域名進(jìn)行監(jiān)聽(tīng),是否能夠發(fā)送數(shù)據(jù)包琼梆,所以初始化的時(shí)候需要一個(gè)socket地址或者域名性誉。
/**
開(kāi)啟網(wǎng)絡(luò)監(jiān)聽(tīng)
*/
- (void)startMonitoring;
/**
停止網(wǎng)絡(luò)監(jiān)聽(tīng)
*/
- (void)stopMonitoring;
/**
返回當(dāng)前網(wǎng)絡(luò)可達(dá)性狀態(tài)對(duì)應(yīng)的本地化文本信息
*/
- (NSString *)localizedNetworkReachabilityStatusString;
/**
設(shè)置網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí)的回調(diào)函數(shù)
*/
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;
接下來(lái)看看具體的實(shí)現(xiàn)
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);
}
}
這個(gè)根據(jù)網(wǎng)絡(luò)狀態(tài)獲取本地化字符串函數(shù)的具體實(shí)現(xiàn)窿吩,這里有一個(gè)NSLocalizedStringFromTable(key, tbl, comment)
函數(shù),是用來(lái)實(shí)現(xiàn)本地化的错览,和NSLocalizedString(key, comment)
不同的是纫雁,前者是用在自定義的tbl.string文件,后者是用在Localizable.strings文件倾哺。
static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {
//獲取可達(dá)狀態(tài)
BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
//是否需要手動(dòng)鏈接
BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
//是否自動(dòng)連接
BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0));
//是否不需要手動(dòng)也鏈接也能自動(dòng)連接
BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0);
//根據(jù)上面的值獲取網(wǎng)絡(luò)可達(dá)性
BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction));
//設(shè)置網(wǎng)絡(luò)狀態(tài)未知
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown;
//不可發(fā)送設(shè)置為AFNetworkReachabilityStatusNotReachable
if (isNetworkReachable == NO) {
status = AFNetworkReachabilityStatusNotReachable;
}
#if TARGET_OS_IPHONE
//如果是蜂窩移動(dòng)網(wǎng)絡(luò)設(shè)置AFNetworkReachabilityStatusReachableViaWWAN
else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) {
status = AFNetworkReachabilityStatusReachableViaWWAN;
}
#endif
//如果是wifi設(shè)置AFNetworkReachabilityStatusReachableViaWiFi
else {
status = AFNetworkReachabilityStatusReachableViaWiFi;
}
return status;
}
這個(gè)就是根據(jù)系統(tǒng)的網(wǎng)絡(luò)狀態(tài)SCNetworkReachabilityFlags
轉(zhuǎn)換為我們自定義的網(wǎng)絡(luò)狀態(tài)AFNetworkReachabilityStatus
轧邪。
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];
});
}
static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
}
第一個(gè)函數(shù)就是根據(jù)系統(tǒng)的網(wǎng)絡(luò)狀態(tài)方法獲取自定義方法,然后用“block”和“通知”兩種方式通知網(wǎng)絡(luò)狀態(tài)的變化羞海。
第二個(gè)函數(shù)就是監(jiān)聽(tīng)到網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí)系統(tǒng)的回調(diào)忌愚,然后函數(shù)內(nèi)部調(diào)用了第一個(gè)函數(shù)去實(shí)現(xiàn)外部通知。
然后就是幾種初始化方法却邓,自己看一下就好了硕糊;還有就是那幾個(gè)網(wǎng)絡(luò)狀態(tài)屬性的get方法,都很簡(jiǎn)單腊徙,也自己看下吧简十。
接下來(lái)就是這個(gè)類的重點(diǎn)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);
}
});
}
先把之前的監(jiān)聽(tīng)停掉,判斷監(jiān)聽(tīng)對(duì)象是不是空昧穿,是空就結(jié)束勺远。
callback
這個(gè)block是在網(wǎng)絡(luò)發(fā)生變化時(shí)系統(tǒng)的回調(diào),在塔的實(shí)現(xiàn)里調(diào)用了外部設(shè)置的網(wǎng)絡(luò)發(fā)生變化時(shí)的blcok回調(diào)时鸵。
/*!
結(jié)構(gòu)體包含了用戶指定的數(shù)據(jù)和SCNetworkReachability的回調(diào)胶逢。
version 結(jié)構(gòu)體的版本號(hào),當(dāng)前版本號(hào)是0饰潜,直接傳0就行了
info 自定義的block函數(shù)指針
retain info的retain操作函數(shù)初坠,可以為空
release info的release操作函數(shù),可以為空
copyDescription 根據(jù)info獲取Description字符串
*/
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è)結(jié)構(gòu)體就是一個(gè)Reachability的上下文彭雾,我們?cè)谏舷挛沫h(huán)境中設(shè)置了Reachability發(fā)生變化時(shí)的回調(diào)碟刺,和回調(diào)函數(shù)的retain、release操作薯酝。
/*!
網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí)的回調(diào)函數(shù)
SCNetworkReachabilityRef 監(jiān)聽(tīng)對(duì)象
SCNetworkReachabilityFlags 網(wǎng)絡(luò)狀態(tài)
info 自定義的block函數(shù)指針
*/
typedef void (*SCNetworkReachabilityCallBack) (
SCNetworkReachabilityRef target,
SCNetworkReachabilityFlags flags,
void * __nullable info
);
/*!
設(shè)置網(wǎng)絡(luò)狀態(tài)變化時(shí)的回調(diào)
SCNetworkReachabilityRef 監(jiān)聽(tīng)對(duì)象
SCNetworkReachabilityCallBack 網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí)的回調(diào)函數(shù)
context 上下文環(huán)境半沽,關(guān)聯(lián)SCNetworkReachabilityCallBack回調(diào)
*/
Boolean
SCNetworkReachabilitySetCallback (
SCNetworkReachabilityRef target,
SCNetworkReachabilityCallBack __nullable callout,
SCNetworkReachabilityContext * __nullable context
)
SCNetworkReachabilitySetCallback
就是把target(監(jiān)聽(tīng)對(duì)象)和context(上下文環(huán)境)中自定義的回調(diào)函數(shù)(AFN中就是剛剛寫的callback函數(shù))還有網(wǎng)絡(luò)狀態(tài)作為callout的參數(shù),在網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí)調(diào)用callout吴菠。
SCNetworkReachabilityScheduleWithRunLoop
就是把監(jiān)聽(tīng)對(duì)象self.networkReachability
加入主線程的runloop中者填,用的是kCFRunLoopCommonModes偽模式。
再后面就是在子線程中主動(dòng)發(fā)出當(dāng)前的網(wǎng)絡(luò)狀態(tài)做葵。
- (void)stopMonitoring {
if (!self.networkReachability) {
return;
}
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
這個(gè)就是停止監(jiān)聽(tīng)占哟,很簡(jiǎn)單,把self.networkReachability
監(jiān)聽(tīng)對(duì)象從runloop中拿出來(lái)就行了。
如有錯(cuò)誤之處榨乎,還請(qǐng)不吝賜教怎燥,謝謝!