AFNetworking知識(shí)點(diǎn)之AFNetworkReachabilityManager

這個(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)不吝賜教怎燥,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蜜暑,一起剝皮案震驚了整個(gè)濱河市铐姚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌史煎,老刑警劉巖谦屑,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驳糯,死亡現(xiàn)場(chǎng)離奇詭異篇梭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)酝枢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門恬偷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人帘睦,你說(shuō)我怎么就攤上這事袍患。” “怎么了竣付?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵诡延,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我古胆,道長(zhǎng)肆良,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任逸绎,我火速辦了婚禮惹恃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘棺牧。我一直安慰自己巫糙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布颊乘。 她就那樣靜靜地躺著参淹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乏悄。 梳的紋絲不亂的頭發(fā)上浙值,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天,我揣著相機(jī)與錄音纲爸,去河邊找鬼亥鸠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的负蚊。 我是一名探鬼主播神妹,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼家妆!你這毒婦竟也來(lái)了鸵荠?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤伤极,失蹤者是張志新(化名)和其女友劉穎蛹找,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體哨坪,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡庸疾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了当编。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片届慈。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖忿偷,靈堂內(nèi)的尸體忽然破棺而出金顿,到底是詐尸還是另有隱情,我是刑警寧澤鲤桥,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布揍拆,位于F島的核電站,受9級(jí)特大地震影響茶凳,放射性物質(zhì)發(fā)生泄漏嫂拴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一慧妄、第九天 我趴在偏房一處隱蔽的房頂上張望顷牌。 院中可真熱鬧,春花似錦塞淹、人聲如沸窟蓝。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)运挫。三九已至,卻和暖如春套耕,著一層夾襖步出監(jiān)牢的瞬間谁帕,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工冯袍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匈挖,地道東北人碾牌。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像儡循,于是被迫代替她去往敵國(guó)和親舶吗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)择膝、插件誓琼、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,120評(píng)論 4 61
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,288評(píng)論 25 707
  • 眼前的沙城真的如沙漠一般,堆滿了大大小小的沙粒肴捉,人們的生活困難重重腹侣。這幾天,沙子沒(méi)過(guò)了小腿齿穗,眼看就快要到膝蓋了傲隶。 ...
    木晴閱讀 292評(píng)論 0 1
  • 親愛(ài)的,最近你還好嗎缤灵?天冷有沒(méi)有多加衣伦籍?有沒(méi)有吃飽飯?學(xué)習(xí)壓力大不大腮出?你可知道,現(xiàn)在的我突然好想你芝薇。我們從一開(kāi)始就...
    深秋知涼閱讀 363評(píng)論 0 0
  • 你的身邊有一些小貓小狗吧胚嘲,對(duì)于這些用它們一生陪伴過(guò)你的小東西們,你是否有一種特殊的情愫洛二,猶如親人般的對(duì)待它...
    咔咔卡巴閱讀 175評(píng)論 0 0