該文章閱讀的AFNetworking的版本爲3.2.0。html
該類主要是用來檢測網絡環境的變化。ios
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1,
AFNetworkReachabilityStatusNotReachable = 0,
AFNetworkReachabilityStatusReachableViaWWAN = 1,
AFNetworkReachabilityStatusReachableViaWiFi = 2,
};
複製代碼
這個枚舉提供了能夠監控的網絡狀態:bash
AFNetworkReachabilityStatusUnknown
網絡狀態未知 AFNetworkReachabilityStatusNotReachable
網絡狀態無鏈接 AFNetworkReachabilityStatusReachableViaWWAN
網絡狀態爲蜂窩移動網絡鏈接 AFNetworkReachabilityStatusReachableViaWiFi
網絡狀態爲無線局域網鏈接網絡
/**
當前網絡鏈接狀態
*/
@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
/**
當前是否有網絡鏈接
*/
@property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
/**
當前網絡鏈接狀態是否爲蜂窩移動網絡鏈接
*/
@property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;
/**
當前網絡鏈接狀態是否爲無線局域網鏈接
*/
@property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;
複製代碼
/**
獲取單例對象
*/
+ (instancetype)sharedManager;
/**
實例化默認socket地址的對象,並主動監視默認socket地址的狀態
*/
+ (instancetype)manager;
/**
實例化指定域的對象,並主動監視指定域的狀態
*/
+ (instancetype)managerForDomain:(NSString *)domain;
/**
實例化指定socket地址的對象,並主動監視指定socket地址的狀態
*/
+ (instancetype)managerForAddress:(const void *)address;
/**
以指定SCNetworkReachabilityRef對象進行初始化,並主動監視指定SCNetworkReachabilityRef對象的狀態
*/
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
/**
初始化方法,這個方法被手動禁止了,若是強制調用這個方法就會報錯
*/
- (nullable instancetype)init NS_UNAVAILABLE;
/**
開始監控網絡狀態
*/
- (void)startMonitoring;
/**
中止監控網絡狀態
*/
- (void)stopMonitoring;
/**
得到網絡狀態的本地文字描述
*/
- (NSString *)localizedNetworkReachabilityStatusString;
/**
當網絡狀態發生變化時,會回調block
*/
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;
複製代碼
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;
複製代碼
這兩個常量是用在經過通知來監聽網絡狀態變化。當須要用通知來監聽網絡狀態變化時,先監聽AFNetworkingReachabilityDidChangeNotification
通知,而後在通知調用的方法中獲取傳遞過來參數中的屬性userInfo
,這個屬性是NSDictionary
類型的,經過key值AFNetworkingReachabilityNotificationStatusItem
就能夠得到當前的網絡狀態。併發
FOUNDATION_EXPORT NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);
複製代碼
這個方法的做用是將傳入的網絡狀態枚舉值轉成本地文字描述。dom
NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";
NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";
複製代碼
爲.h
文件中全局靜態常量賦值異步
typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);
複製代碼
爲參數爲AFNetworkReachabilityStatus
類型無返回值的block起名爲AFNetworkReachabilityStatusBlock
socket
/**
這個方法就是.h文件最後一個方法的實現,用來將傳入的網絡狀態枚舉值轉成本地文字描述
*/
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);
}
}
/**
該方法是將SCNetworkReachabilityFlags類型的枚舉轉換成AFNetworking自定義的網絡狀態枚舉
*/
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;
}
/**
爲了保證網絡狀態變化時block回調和發送通知的統一性,將二者在主線程統一調用
*/
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
// 將flags轉成自定義網絡狀態枚舉值
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
// 主隊列異步
dispatch_async(dispatch_get_main_queue(), ^{
// 回調block
if (block) {
block(status);
}
// 發送通知
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
[notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
});
}
/**
將上面的方法封裝,做爲參數傳入網絡狀態監控回調方法SCNetworkReachabilitySetCallback中
*/
static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
}
/**
將block複製到堆中,並封裝成方法做爲參數構建SCNetworkReachabilityContext結構體
*/
static const void * AFNetworkReachabilityRetainCallback(const void *info) {
return Block_copy(info);
}
/**
釋放複製到堆中的block,並封裝成方法做爲參數構建SCNetworkReachabilityContext結構體
*/
static void AFNetworkReachabilityReleaseCallback(const void *info) {
if (info) {
Block_release(info);
}
}
複製代碼
/**
保存傳入的SCNetworkReachabilityRef對象
*/
@property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;
/**
保存當前網絡狀態的枚舉值
*/
@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
/**
保存傳入的用於回調的block
*/
@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
複製代碼
+ (instancetype)sharedManager {
// 調用以默認socket地址實例化對象的方法,生成單例對象
static AFNetworkReachabilityManager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedManager = [self manager];
});
return _sharedManager;
}
+ (instancetype)managerForDomain:(NSString *)domain {
// 利用傳入的域生成SCNetworkReachabilityRef對象
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
// 利用SCNetworkReachabilityRef對象實例化AFNetworkReachabilityManager對象
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
// 釋放SCNetworkReachabilityRef對象
CFRelease(reachability);
return manager;
}
+ (instancetype)managerForAddress:(const void *)address {
// 利用傳入的地址象實例化AFNetworkReachabilityManager對象
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
// 利用SCNetworkReachabilityRef對象實例化AFNetworkReachabilityManager對象
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
// 釋放SCNetworkReachabilityRef對象
CFRelease(reachability);
return manager;
}
+ (instancetype)manager
{
// 根據版本號適配IPv6和IPv4,得到默認地址
#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;
}
- (instancetype)init NS_UNAVAILABLE
{
return nil;
}
- (void)dealloc {
// 中止監控
[self stopMonitoring];
// 釋放SCNetworkReachabilityRef對象
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];
// 若是沒有傳入或者生成SCNetworkReachabilityRef對象就直接返回
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);
// 在全局併發隊列中異步監聽SCNetworkReachabilityRef對象的網絡狀態,若是發生變化則進行回調和發送通知
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
AFPostReachabilityStatusChange(flags, callback);
}
});
}
- (void)stopMonitoring {
// 若是沒有傳入或者生成SCNetworkReachabilityRef對象就直接返回
if (!self.networkReachability) {
return;
}
// 將SCNetworkReachabilityRef對象從運行循環中移除
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
- (NSString *)localizedNetworkReachabilityStatusString {
return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus);
}
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
self.networkReachabilityStatusBlock = block;
}
複製代碼
這其中有一點是在使用GCD時傳入了參數DISPATCH_QUEUE_PRIORITY_BACKGROUND
,這個不經常使用的參數有着和AFURLRequestSerialization
類中的throttleBandwidthWithPacketSize:delay:
方法共同的知識點,感興趣的話能夠看這篇文章async
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) {
return [NSSet setWithObject:@"networkReachabilityStatus"];
}
return [super keyPathsForValuesAffectingValueForKey:key];
}
複製代碼
添加依賴鍵,使reachable
、reachableViaWWAN
和reachableViaWiFi
屬性依賴於networkReachabilityStatus
屬性,當networkReachabilityStatus
屬性值發生變化時,reachable
、reachableViaWWAN
和reachableViaWiFi
屬性的觀察者也能獲得通知。oop
源碼閱讀系列:AFNetworking
源碼閱讀:AFNetworking(二)——AFURLRequestSerialization
源碼閱讀:AFNetworking(三)——AFURLResponseSerialization
源碼閱讀:AFNetworking(四)——AFSecurityPolicy
源碼閱讀:AFNetworking(五)——AFNetworkReachabilityManager
源碼閱讀:AFNetworking(六)——AFURLSessionManager
源碼閱讀:AFNetworking(七)——AFHTTPSessionManager
源碼閱讀:AFNetworking(八)——AFAutoPurgingImageCache
源碼閱讀:AFNetworking(九)——AFImageDownloader
源碼閱讀:AFNetworking(十)——AFNetworkActivityIndicatorManager
源碼閱讀:AFNetworking(十一)——UIActivityIndicatorView+AFNetworking
源碼閱讀:AFNetworking(十二)——UIButton+AFNetworking
源碼閱讀:AFNetworking(十三)——UIImageView+AFNetworking
源碼閱讀:AFNetworking(十四)——UIProgressView+AFNetworking