转自:http://blog.csdn.net/drift_axe/article/details/51463835点击打开链接
概述
iOS开发中,经常要根据实时的网络状况,对UI及逻辑做出调整,以提高用户的使用体验。
方案
方案一:使用苹果封装的Reachability进行网络检测
如何下载Reachability?
打开Xcode,用快捷键(shift + command + 0)打开并搜索Reachability,如下图,下载即可。
示例代码:
- #import "Reachability.h"
- @interface LeftViewController ()
- @property (strong, nonatomic) Reachability *reachability;
- @end
- @implementation LeftViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- // 此处一定要声明全局变量,否则通知是不会执行的
- self.reachability = [Reachability reachabilityForInternetConnection];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityStatusChange:) name:kReachabilityChangedNotification object:_reachability];
- [_reachability startNotifier];
- }
- - (void)reachabilityStatusChange:(NSNotification *)notification {
- Reachability *reachability = (Reachability *)[notification object];
- NSParameterAssert([reachability isKindOfClass:[Reachability class]]);
- NetworkStatus status = [reachability currentReachabilityStatus];
- NSLog(@"%ld",(long)status);
- }
问题1:由于上述的监测方式是利用KVO机制,所以是在网络状态变化后才会收到通知,并不是严格意义上的实时检测网络。我们大部分是需要在点击某个按钮,进行网络请求的时候,会检测网络状况,如果没有网络,那就没必要去做请求操作。这时你可以用弹窗的形式提示用户检查网络设置。况且每个视图控制器里都要去注册通知,在控制器销毁的时候移除通知,是个很繁琐的过程,也不利于代码维护(当然你在父视图控制器里用此方法,其他控制器都继承之)。
问题2:由于默认只提供了三种网络状态:NotReachable、reachableViaWiFi和reachableViaWWAN,如果我们要区分2G/3G/4G网络,则需要对Reachability进行相应的更改。
- typedef enum : NSInteger {
- NotReachable = 0,
- ReachableViaWiFi,
- ReachableViaWWAN,
- ReachableVia2G,
- ReachableVia3G,
- ReachableVia4G
- } NetworkStatus;
在源码的基础上,添加2G/3G/4G枚举状态,接下来在.m中修改方法:- networkStatusForFlags:
- - (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags {
- PrintReachabilityFlags(flags, "networkStatusForFlags");
- if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
- {
- // The target host is not reachable.
- return NotReachable;
- }
- NetworkStatus returnValue = NotReachable;
- if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
- {
- /*
- If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
- */
- returnValue = ReachableViaWiFi;
- }
- if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
- (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
- {
- /*
- ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
- */
- if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
- {
- /*
- ... and no [user] intervention is needed...
- */
- returnValue = ReachableViaWiFi;
- }
- }
- if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
- {
- /*
- ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
- */
- if (NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0) {
- CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
- NSString *currentRadioAccessTechnology = info.currentRadioAccessTechnology;
- if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {
- returnValue = ReachableVia4G;
- } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS]) {
- returnValue = ReachableVia2G;
- } else {
- returnValue = ReachableVia3G;
- }
- return returnValue;
- }
- if ((flags && kSCNetworkReachabilityFlagsTransientConnection) == kSCNetworkReachabilityFlagsTransientConnection) {
- if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == kSCNetworkReachabilityFlagsConnectionRequired) {
- returnValue = ReachableVia2G;
- return returnValue;
- }
- returnValue = ReachableVia3G;
- return returnValue;
- }
- returnValue = ReachableViaWWAN;
- }
- return returnValue;
- }
方案二:使用AFNetworkReachabilityManager进行网络监测
此类处于AFNetworking第三方库中,可自行下载。
- #import "AppDelegate.h"
- @interface AppDelegate ()
- @end
- @implementation AppDelegate
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- // Override point for customization after application launch.
- // 在此全程检测网络状态,全局可以获取当前的网络状态
- AFNetworkReachabilityManager *networkReachabilityManager = [AFNetworkReachabilityManager sharedManager];
- [networkReachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
- // insert your code ...
- }];
- [networkReachabilityManager startMonitoring];
- }
在需要的地方,调用下面的方法,便可知道目前的网络状态。
- - (AFNetworkReachabilityStatus)networkReachabilityStatus {
- return [AFNetworkReachabilityManager sharedManager].networkReachabilityStatus;
- }
方案三:使用RealReachability进行实时网络检测
如果我们连接上一个公用WiFi后,用上面两种方式监测网络,其结果都认为你的APP已经连接上了网络,但实际上只是本地连接上,并没有真正接入网络,大家应该有体会。RealReachability提供了实时网络监测的功能,详情可参考链接:点击打开链接。