亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

AFNetworking 3.0 源碼解讀(1)

2019-11-09 17:54:16
字體:
來源:轉載
供稿:網友

AFNetworkReachabilityManager (監控網絡環境變化的類)

這個分析是我在讀AFNetworking 3.0 源碼解系列寫的,很多想法都是來自他的文章,非常感謝作者的分享精神!

//AFNetworkReachabilityManager.h

分析

1.這個類是基于SCNetworkReachabilityRef這個系統類來實現的,提供了和聯網相關的函數。可參考這個。 2.打開和關閉監聽網絡變化的方法

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

3.網絡狀態改變時,監聽的回調有兩種方法: a.通過監聽AFNetworkingReachabilityDidChangeNotification這個通知。 b.通過下面這個方法。

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

啟發

1.可以用一些特殊的格式注釋,或者PRagma mark等來進行分隔不同功能模塊的代碼。如下圖@name Initialization

@property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;///---------------------/// @name Initialization///---------------------/** Returns the shared network reachability manager. */+ (instancetype)sharedManager;

2.BOOL類型的值,若只允許訪問可設置成getter,然后給予一個更明確的getter、setter方法名來替代默認生成的方法名(即變量名、set+變量名)。 在.h中聲明為readonly的屬性,可以再類別中再聲明一次為readwrite,這樣在.m中可以進行讀寫。

//.h@property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;//注意這里是`readonly`@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;//.m@interface AFNetworkReachabilityManager ()//這里是`readwrite`@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;@end- (BOOL)isReachable { return [self isReachableViaWWAN] || [self isReachableViaWiFi];}

3.關于定義常量方面的格式一般有兩種,普通的就是#define kMyConstantString @"Hello",另一種如下:

//.h///--------------------/// @name Notifications///--------------------FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;///--------------------/// @name Functions///--------------------/** Returns a localized string representation of an `AFNetworkReachabilityStatus` value. */FOUNDATION_EXPORT NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);//.mNSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);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); }}

使用第二種方式定義的字符串,在比較的時候速度更快,可以直接使用(stringInstance == MyFirstConstant)來比較,而define則使用的是這種.([stringInstance isEqualToString:MyFirstConstant])。 第二種直接比較的是指針地址,而第一個則是一一比較字符串的每一個字符是否相等。 這種定義可以多用于NSNotification的字符串定義。

4.NS_DESIGNATED_INITIALIZERNS_UNAVAILABLE的配合使用:

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

NS_DESIGNATED_INITIALIZER用來標記指定構造器,即你希望初始化對象時所使用的指定函數。如果子類指定了新的初始化器,那么在這個初始化器內部必須調用父類的Designated Initializer。并且需要重寫父類的Designated Initializer,將其指向子類新的初始化器。如下:

// .h- (instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER;// .m- (instancetype)init{ return [self initWithName:@""];}- (instancetype)initWithName:(NSString *)name{ self = [super init]; if (self) { // do something } return self;}

但是往往,我們是不希望子類用其他的初始化方法的,所以可以用NS_UNAVAILABLE來標記繼承來的init方法,讓它變為不可用,成為私有的方法。即外部調用alloc init會報錯。

//AFNetworkReachabilityManager.m

分析

1.網絡狀態改變時的通知

//網絡環境發生改變時接收的通知NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";//上面的通知發送時,會攜帶一組狀態數據,根據這個key從userinfo中取出網絡statusNSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";//使用- (void)verifyReachabilityNotificationGetsPostedWithManager:(AFNetworkReachabilityManager *)manager{ [self expectationForNotification:AFNetworkingReachabilityDidChangeNotification object:nil handler:^BOOL(NSNotification *note) { AFNetworkReachabilityStatus status; status = [note.userInfo[AFNetworkingReachabilityNotificationStatusItem] integerValue]; BOOL isReachable = (status == AFNetworkReachabilityStatusReachableViaWiFi || status == AFNetworkReachabilityStatusReachableViaWWAN); return isReachable; }]; [manager startMonitoring]; [self waitForExpectationsWithCommonTimeout];}

2.將SCNetworkReachabilityRef文件中用來表示網絡狀態的SCNetworkReachabilityFlags 轉化成平時常用的狀態,即本類AFNetworkReachabilityStatus的值。

/** * 根據SCNetworkReachabilityFlags這個網絡標記來轉換成我們在開發中經常使用的網絡狀態 1.不能連接網絡 2.蜂窩連接 3.WiFi連接 4.未知連接 */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); // 是否可以聯網的條件 1.能夠到達 2.不需要建立連接或者不需要用戶手動設置連接 就表示能夠連接到網絡 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;}

3.監聽網絡變化有兩個方法,block和NSNotification, 為了讓這兩個方法的值保持一致,將兩個過程封裝到同一個函數中,一旦發生網絡變化,對調用這個函數

static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) { AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); dispatch_async(dispatch_get_main_queue(), ^{ if (block) { //有block就調用block block(status); } //發通知 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; //用到了AFNetworkingReachabilityNotificationStatusItem作為key來存status,接收到通知時,再通過這個key取出status NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) }; [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo]; });}

4.單例創建方法,注意宏定義,這里的宏定義可以減少書寫ifelse的判斷

+ (instancetype)sharedManager { static AFNetworkReachabilityManager *_sharedManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _sharedManager = [self manager]; }); return _sharedManager;}+ (instancetype)manager { //涉及到IPv6所以要判斷版本 //__IPHONE_OS_VERSION_MIN_REQUIRED iphone系統 //__IPHONE_OS_VERSION_MIN_REQUIRED >= 90000 系統版本9.0及以上#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];}

5.開啟網絡監聽 首先要了解一下SCNetworkReachabilityContext,這是一個結構體:

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;//1. 第一個參數接受一個signed long 的參數//2. 第二個參數info接受一個void * 類型的值,相當于oc的id類型,void * 可以指向任何類型的參數,本類中的info是一個block.//3. 第三個參數 是一個函數 目的是對info做retain操作,//4. 第四個參數是一個函數,目的是對info做release操作//5. 第五個參數是 一個函數,根據info獲取Description字符串

retain和release 函數是下邊的這兩個函數,寫在.m文件最前面

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

具體開啟監控的代碼:

- (void)startMonitoring { [self stopMonitoring]; if (!self.networkReachability) { return; } //這個block就是用來傳入SCNetworkReachabilityContext的info __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}; //設置回調,AFNetworkReachabilityCallback執行時可以傳入一個block作為參數,這里傳入的就是上面的callback,即context里的info SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); //加入RunLoop池 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); } });}

其中AFNetworkReachabilityCallback的定義如下,是根據SCNetworkReachabilitySetCallback第二個參數類型來聲明的:

//target其實在這里并沒有使用到,這是為了滿足SCNetworkReachabilitySetCallback參數的定義而聲明的,所以用__unused聲明static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);}

6.鍵值依賴,這段代碼在.m文件的最后,可以溫習一下kvc、kvo的相關知識。

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

啟發

1.NS_ENUMNS_OPTIONS都是常用的枚舉聲明方法,NS_OPTIONS是按位掩碼,NS_ENUM枚舉項的值為NSInteger,NS_OPTIONS枚舉項的值為NSUInteger;NS_ENUM定義通用枚舉,NS_OPTIONS定義位移枚舉。位移枚舉即是在你需要的地方可以同時存在多個枚舉值,而NS_ENUM定義的枚舉不能幾個枚舉項同時存在,只能選擇其中一項。 NS_OPTIONS可以表示幾個選項的各種組合,用|表示,當判斷這個組合是否包含某個單獨的枚舉值時可以進行&操作。如分析.m的第一點中代碼所示。

typedef NS_OPTIONS(NSUInteger, UISwipeGestureRecognizerDirection) { UISwipeGestureRecognizerDirectionNone = 0, //值為0 UISwipeGestureRecognizerDirectionRight = 1 << 0, //值為2的0次方 UISwipeGestureRecognizerDirectionLeft = 1 << 1, //值為2的1次方 UISwipeGestureRecognizerDirectionUp = 1 << 2, //值為2的2次方 UISwipeGestureRecognizerDirectionDown = 1 << 3 //值為2的3次方};

2.類中的私有方法可以用c函數來寫,eg:static void funcName() a.在文件的最前方,比較容易查找 b. 可以適當的使用內聯函數(static inline),內聯函數在編譯的時候,會把代碼直接嵌入調用代碼中。就相當于用#define 宏定義來定義一個 函數,避免了使用call指令,提高效率

//.mstatic AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {...}static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {...}@interface AFNetworkReachabilityManager ()//.......@end@implementation AFNetworkReachabilityManager//......@end

3.__unused前綴,就可以免除警告。其原理是告訴編譯器,如果變量未使用就不參與編譯。

static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亲子乱一区二区三区电影| 久久久久99精品久久久久| 日韩电影免费在线观看中文字幕| 亚洲第一区在线观看| 国产脚交av在线一区二区| 3344国产精品免费看| 久久久久国产精品免费网站| 欧美激情伊人电影| 精品福利免费观看| 欧美xxxx做受欧美.88| 成人网中文字幕| 国产999精品| 日韩高清免费观看| 久久久久久久电影一区| 成人黄色大片在线免费观看| 国产又爽又黄的激情精品视频| 亚洲视频专区在线| 欧美香蕉大胸在线视频观看| 日本一本a高清免费不卡| 国产91九色视频| 欧美极品少妇与黑人| 亚洲一区亚洲二区亚洲三区| 亚洲男人天堂2024| 亚洲午夜激情免费视频| 国产亚洲欧洲高清一区| 中文日韩电影网站| 美女撒尿一区二区三区| 国产99在线|中文| 精品视频在线播放色网色视频| 亚洲一区av在线播放| 成人黄色激情网| 日韩精品一区二区三区第95| 国产精品亚洲自拍| 亚洲欧美日本另类| 欧美激情a在线| 日韩高清电影免费观看完整版| 中文字幕日韩电影| 久久精品国产清自在天天线| 国产精品自拍偷拍视频| 亚洲无线码在线一区观看| 欧美高清在线观看| 国产日韩在线看片| 亚洲男人的天堂在线| 国产一区二区在线播放| 在线视频欧美性高潮| 欧美性69xxxx肥| 韩国精品美女www爽爽爽视频| 亚洲成人av在线播放| 欧美丝袜一区二区| 色综合天天狠天天透天天伊人| 亚洲欧美国产日韩天堂区| 日韩中文在线中文网三级| 成人在线免费观看视视频| 日韩av在线免播放器| 亚洲精品国产综合区久久久久久久| 国产午夜精品麻豆| 久久夜色精品亚洲噜噜国产mv| 亚洲а∨天堂久久精品9966| 日韩在线不卡视频| 色琪琪综合男人的天堂aⅴ视频| 欧美精品在线视频观看| 亚洲午夜激情免费视频| 8x拔播拔播x8国产精品| 精品视频中文字幕| 亚洲成人av在线| 欧美在线观看日本一区| 海角国产乱辈乱精品视频| 亚洲精品资源美女情侣酒店| 狠狠色狠狠色综合日日五| 久久久久国产视频| 中文字幕无线精品亚洲乱码一区| 亚洲国产天堂网精品网站| 欧美激情亚洲综合一区| 在线成人激情视频| 亚洲男女自偷自拍图片另类| 亚洲精品成人网| 亚洲天堂色网站| 色婷婷av一区二区三区在线观看| 国产亚洲a∨片在线观看| 亚洲国产欧美自拍| 日韩毛片在线观看| 日韩精品视频免费| 久久免费精品视频| 欧美性色视频在线| 欧美日韩一区二区三区| 亚洲综合中文字幕68页| www.久久久久| 国产激情视频一区| 亚洲自拍偷拍色图| 97久久超碰福利国产精品…| 国产99久久精品一区二区 夜夜躁日日躁| 欧美国产日韩免费| 精品免费在线观看| 亚洲成av人片在线观看香蕉| 国产精品久久久久久久美男| 日韩精品一区二区视频| 久久91亚洲精品中文字幕奶水| 日韩在线观看网址| 欧美亚洲一级片| 欧美另类交人妖| 国产精品影片在线观看| 伊人久久大香线蕉av一区二区| 久久影视电视剧免费网站清宫辞电视| 日韩一二三在线视频播| 久久久成人av| 91在线无精精品一区二区| 欧美性猛交xxxx免费看久久久| 亚洲精品免费av| 久久在精品线影院精品国产| 正在播放亚洲1区| 国产成人av网| 久久天天躁日日躁| 555www成人网| 国产精品久久久久久久7电影| 亚洲国产一区二区三区四区| 欧美激情一区二区三区在线视频观看| 日本精品久久中文字幕佐佐木| 国产婷婷成人久久av免费高清| 午夜免费久久久久| 欧美日韩不卡合集视频| 国产精品一区二区性色av| 欧美性xxxxx极品娇小| 久久精品视频导航| 亚洲自拍偷拍视频| 伊人成人开心激情综合网| 国a精品视频大全| 一区二区三区回区在观看免费视频| 成人免费网视频| 欧美激情精品久久久| 日韩在线观看av| 欧美日韩国产丝袜美女| 亚洲天堂网在线观看| 日韩av免费在线看| 97在线观看免费| 久久久精品免费| 欧洲永久精品大片ww免费漫画| 欧美日韩福利电影| 欧美在线视频免费观看| 精品动漫一区二区| 欧美在线视频一区二区| 日韩欧美成人网| 福利视频导航一区| 热re91久久精品国99热蜜臀| 亚洲欧美日韩一区二区三区在线| 日韩成人av在线| 国产精品视频yy9099| 亚洲男人天堂网站| 国产精品美女主播在线观看纯欲| 欧美激情国内偷拍| 国产日韩欧美夫妻视频在线观看| 美日韩丰满少妇在线观看| 欧美性xxxx极品高清hd直播| 日本久久久久久| 在线日韩欧美视频| 色偷偷888欧美精品久久久| 在线日韩第一页| 欧美激情一二三| 青青草一区二区| 亚洲综合成人婷婷小说| 久久国产精品久久精品| 国产精品r级在线| 最近2019中文免费高清视频观看www99| 一区二区三区美女xx视频| 国产精品无码专区在线观看|