ios-研究AFNetworking(1)-AFNetworkReachabilityManager類

來源:互聯網
上載者:User

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;    }#ifTARGET_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的分析就講到這裡,以後遇到實際應用,再回來補充實際使用方式......

















































相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.