|
转自:http://blog.iyunv.com/devfun/article/details/7365774
由于设计的游戏需要有一些联网请求,但有时候在设备未连接网络的情况下,如果对网络情况不加以判断,则可能造成游戏为了等游戏超时,浪费不必要的时间。
所以在游戏启动时检测一下网络状况是很必要的,而且当玩家的设备连接上网络以后,有一个回调函数也是非常必要的一件事儿,这样可能更方便我们在后台下载数据库等信息。
apple为我们提供了一套范例代码,下面我就来分析一下这段代码。
范例代码地址在:https://developer.apple.com/library/ios/#samplecode/Reachability/Listings/Classes_ReachabilityAppDelegate_m.html#//apple_ref/doc/uid/DTS40007324-Classes_ReachabilityAppDelegate_m-DontLinkElementID_4
范例中包含两部分,一部分是appdelegate,一部分是reachability
1 #import <sys/socket.h>
2 #import <netinet/in.h>
3 #import <netinet6/in6.h>
4 #import <arpa/inet.h>
5 #import <ifaddrs.h>
6 #import <netdb.h>
7
8 #import <CoreFoundation/CoreFoundation.h>
9
10 #import "Reachability.h"
11
12 #define kShouldPrintReachabilityFlags 1
13
14 static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
15 {
16 #if kShouldPrintReachabilityFlags
17
18 NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
19 (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',//当前网络为蜂窝网络,即3G或者GPRS
20 (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',//网络请求地址可达
21
22 (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
23 (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
24 (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
25 (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
26 (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
27 (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',//该值为一个本地地址
28 (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
29 comment
30 );
31 #endif
32 }
33
34
35 @implementation Reachability
36 static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
37 {
38 #pragma unused (target, flags)
39 NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
40 NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
41
42 //We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
43 // in case someon uses the Reachablity object in a different thread.
44 NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
45
46 Reachability* noteObject = (Reachability*) info;
47 // Post a notification to notify the client that the network reachability changed.
48 [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
49
50 [myPool release];
51 }
52
53
54
55 //启动探测网络
56 - (BOOL) startNotifier
57 {
58 BOOL retVal = NO;
59 SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
60 //SCNetworkReachabilitySetCallback函数为指定一个target(此处为reachabilityRef,即www.apple.com,在reachabilityWithHostName里设置的)
61 //当设备对于这个target链接状态发生改变时(比如断开链接,或者重新连上),则回调reachabilityCallback函数,
62 if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
63 {
64 //指定一个runloop给指定的target
65 if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
66 {
67 retVal = YES;
68 }
69 }
70 return retVal;
71 }
72 //停止网络探测
73 - (void) stopNotifier
74 {
75 if(reachabilityRef!= NULL)
76 {
77 SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
78 }
79 }
80
81 - (void) dealloc
82 {
83 [self stopNotifier];
84 if(reachabilityRef!= NULL)
85 {
86 CFRelease(reachabilityRef);
87 }
88 [super dealloc];
89 }
90 //通过域名设定一个目标地址比如www.apple.com
91 + (Reachability*) reachabilityWithHostName: (NSString*) hostName;
92 {
93 Reachability* retVal = NULL;
94 SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
95 if(reachability!= NULL)
96 {
97 retVal= [[[self alloc] init] autorelease];
98 if(retVal!= NULL)
99 {
100 retVal->reachabilityRef = reachability;
101 retVal->localWiFiRef = NO;
102 }
103 }
104 return retVal;
105 }
106 //通过ip地址设定一个目标的地址,可以加端口号,貌似我实验的不太成功
107 + (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
108 {
109 SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
110 Reachability* retVal = NULL;
111 if(reachability!= NULL)
112 {
113 retVal= [[[self alloc] init] autorelease];
114 if(retVal!= NULL)
115 {
116 retVal->reachabilityRef = reachability;
117 retVal->localWiFiRef = NO;
118 }
119 }
120 return retVal;
121 }
122 //检测当前网络能否连上internet
123 + (Reachability*) reachabilityForInternetConnection;
124 {
125 struct sockaddr_in zeroAddress;
126 bzero(&zeroAddress, sizeof(zeroAddress));
127 zeroAddress.sin_len = sizeof(zeroAddress);
128 zeroAddress.sin_family = AF_INET;
129 return [self reachabilityWithAddress: &zeroAddress];
130 }
131 //检测当前网络是否能够连上本地wifi
132 + (Reachability*) reachabilityForLocalWiFi;
133 {
134 struct sockaddr_in localWifiAddress;
135 bzero(&localWifiAddress, sizeof(localWifiAddress));
136 localWifiAddress.sin_len = sizeof(localWifiAddress);
137 localWifiAddress.sin_family = AF_INET;
138 // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
139 localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
140 Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress];
141 if(retVal!= NULL)
142 {
143 retVal->localWiFiRef = YES;
144 }
145 return retVal;
146 }
147
148 #pragma mark Network Flag Handling
149
150 - (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags
151 {
152 PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
153
154 BOOL retVal = NotReachable;
155 if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
156 {
157 retVal = ReachableViaWiFi;
158 }
159 return retVal;
160 }
161 //通过flags返回当前网络状态
162 - (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags
163 {
164 PrintReachabilityFlags(flags, "networkStatusForFlags");
165 if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
166 {
167 // if target host is not reachable
168 return NotReachable;
169 }
170
171 BOOL retVal = NotReachable;
172
173 if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
174 {
175 // if target host is reachable and no connection is required
176 // then we'll assume (for now) that your on Wi-Fi
177 retVal = ReachableViaWiFi;
178 }
179
180
181 if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
182 (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
183 {
184 // ... and the connection is on-demand (or on-traffic) if the
185 // calling application is using the CFSocketStream or higher APIs
186
187 if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
188 {
189 // ... and no [user] intervention is needed
190 retVal = ReachableViaWiFi;
191 }
192 }
193
194 if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
195 {
196 // ... but WWAN connections are OK if the calling application
197 // is using the CFNetwork (CFSocketStream?) APIs.
198 retVal = ReachableViaWWAN;
199 }
200 return retVal;
201 }
202
203 - (BOOL) connectionRequired;
204 {
205 NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
206 SCNetworkReachabilityFlags flags;
207 if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
208 {
209 return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
210 }
211 return NO;
212 }
213 //获得当前网络状态
214 - (NetworkStatus) currentReachabilityStatus
215 {
216 NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");
217 NetworkStatus retVal = NotReachable;
218 SCNetworkReachabilityFlags flags;
219 if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
220 {
221 if(localWiFiRef)
222 {
223 retVal = [self localWiFiStatusForFlags: flags];
224 }
225 else
226 {
227 retVal = [self networkStatusForFlags: flags];
228 }
229 }
230 return retVal;
231 }
232 @end
以上的部分为具体实现的部分,下面我们再来看在appdelegate里面调用的部分
- (void) applicationDidFinishLaunching: (UIApplication* )application
{
#pragma unused(application)
contentView.backgroundColor = [UIColor groupTableViewBackgroundColor];
summaryLabel.hidden = YES;
//这句是设定一个回调函数reachability,当网络条件发生变化时则去调用reachabilityChanged
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(reachabilityChanged:) name: kReachabilityChangedNotification object: nil];
//Change the host name here to change the server your monitoring
remoteHostLabel.text = [NSString stringWithFormat: @"Remote Host: %@", @"www.apple.com"];
//设定target地址,这里是www.apple.com
hostReach = [[Reachability reachabilityWithHostName: @"www.apple.com"] retain];
//启动网络条件检测
[hostReach startNotifier];
//更新UI的网络状态显示
[self updateInterfaceWithReachability: hostReach];
//探测是否能连上internet网
internetReach = [[Reachability reachabilityForInternetConnection] retain];
[internetReach startNotifier];
[self updateInterfaceWithReachability: internetReach];
//探测wifi是否开启
wifiReach = [[Reachability reachabilityForLocalWiFi] retain];
[wifiReach startNotifier];
[self updateInterfaceWithReachability: wifiReach];
[window makeKeyAndVisible];
}
//如需要查看网络状态,如下调用即可
NetworkStatus netStatus = [curReach currentReachabilityStatus];
netStatus有ReachableViaWWAN(蜂窝网络3G之类的),ReachableViaWiFi(wifi连接),NotReachable(无法连接)
|
|
|