iOS開發之runtime的運用-獲取當前網絡狀態


原文地址:http://www.360doc.com/content/15/0702/09/26463620_482084266.shtml#


之前寫過runtime的一些東西,這次通過runtime獲取一些蘋果官方不想讓你拿到的東西,比如,狀態欄內部的控件屬性。本文將通過runtime帶你一步步拿到狀態欄中顯示網絡狀態的控件,然後通過監測該控件的屬性來獲取當前精確網絡狀態,比如2G/3G/4G/WIFI。

首先,我們需要拿到狀態欄,然後通過runtime去探討狀態欄內部的組成結構。
1、導入運行時頭文件
#import <objc/message.h>
2、編寫運行時代碼,獲取到當前應用程序的所有成員變量
複製代碼
 1 #import "ViewController.h"
 2 #import <objc/message.h>
 3 
 4 @interface ViewController ()
 5 
 6 @end
 7 
 8 @implementation ViewController
 9 
10 - (void)viewDidAppear:(BOOL)animated
11 {
12     // 狀態欄是由當前app控制的,首先獲取當前app
13     UIApplication *app = [UIApplication sharedApplication];
14     
15     // 遍歷當前app的所有屬性,找到關於狀態欄的
16     unsigned int outCount = 0;
17     
18     Ivar *ivars = class_copyIvarList(app.class, &outCount);
19     
20     for (int i = 0; i < outCount; i++) {
21         Ivar ivar = ivars[i];
22         printf("|%s", ivar_getName(ivar));
23     }
24 }
25 
26 @end
複製代碼
直接運行,可以看到打印結果爲:
3、可以看app裏確實有個關於狀態欄的成員變量,我們通過KVC取出它
複製代碼
 1 - (void)viewDidAppear:(BOOL)animated
 2 {
 3     // 狀態欄是由當前app控制的,首先獲取當前app
 4     UIApplication *app = [UIApplication sharedApplication];
 5     
 6     id statusBar = [app valueForKeyPath:@"statusBar"];
 7     
 8     // 遍歷狀態欄的所有成員
 9     unsigned int outCount = 0;
10     Ivar *ivars = class_copyIvarList([statusBar class], &outCount);
11     
12     for (int i = 0; i < outCount; i++) {
13         Ivar ivar = ivars[i];
14         printf("|%s", ivar_getName(ivar));
15     }
16 }
複製代碼
運行後可以看到打印結果爲
4、狀態欄裏有foregroundView這個成員,應該代表着所有當前顯示的視圖,通過KVC取出它裏面的所有子視圖
複製代碼
1 // 狀態欄是由當前app控制的,首先獲取當前app
2     UIApplication *app = [UIApplication sharedApplication];
3     
4     NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
5     
6     for (id child in children) {
7         NSLog(@"--%@", [child class]);
8     }
複製代碼
打印結果爲
5、遍歷數組,取出用於顯示網絡狀態的視圖,並遍歷其內部的所有成員變量
複製代碼
 1 // 狀態欄是由當前app控制的,首先獲取當前app
 2     UIApplication *app = [UIApplication sharedApplication];
 3     
 4     NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
 5     
 6     for (id child in children) {
 7         if ([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
 8             // 遍歷當前狀態欄的所有屬性,找到關於狀態欄的
 9             unsigned int outCount = 0;
10             Ivar *ivars = class_copyIvarList([child class], &outCount);
11             
12             for (int i = 0; i < outCount; i++) {
13                 Ivar ivar = ivars[i];
14                 printf("|%s", ivar_getName(ivar));
15             }
16         }
17     }
複製代碼
打印結果爲
6、下面通過KVC,取出dataNetworkType
1 if ([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
2             id type = [child valueForKeyPath:@"dataNetworkType"];
3             NSLog(@"_dataNetworkType class is %@, value is %@", [type class], type);
4         }
打印結果爲: 
可見,dataNetworkType類型是NSNumber,值是5。【以上均爲模擬器測試】
經過測試,發現,可能的值爲 1,2,3,5 分別對應的網絡狀態是2G、3G、4G及WIFI。 當沒有網絡時,隱藏UIStatusBarDataNetworkItemView,無法獲取dataNetworkType值
總結:
以下是完整的代碼,並經過真機測試:
複製代碼
 1 - (void)viewDidAppear:(BOOL)animated
 2 {
 3     // 狀態欄是由當前app控制的,首先獲取當前app
 4     UIApplication *app = [UIApplication sharedApplication];
 5     
 6     NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
 7     
 8     int type = 0;
 9     for (id child in children) {
10         if ([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
11             type = [[child valueForKeyPath:@"dataNetworkType"] intValue];
12         }
13     }
14     NSLog(@"----%d", type); 
15 }
複製代碼
打印出的type數字對應的網絡狀態依次是:0 - 無網絡; 1 - 2G; 2 - 3G; 3 - 4G; 5 - WIFI
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章