├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── VZInspector.podspec ├── VZInspector ├── VZDefine.h ├── VZInspector.h ├── VZInspector.m ├── core │ ├── NSObject+VZInspector.h │ ├── NSObject+VZInspector.m │ ├── VZInspectController.h │ ├── VZInspectController.m │ ├── VZInspectorAssert.h │ ├── VZInspectorOverlay.h │ ├── VZInspectorOverlay.m │ ├── VZInspectorResource.h │ ├── VZInspectorResource.m │ ├── VZInspectorTimer.h │ ├── VZInspectorTimer.m │ ├── VZInspectorUtility.h │ ├── VZInspectorUtility.m │ ├── VZInspectorView.h │ ├── VZInspectorView.m │ ├── VZInspectorWindow.h │ ├── VZInspectorWindow.m │ ├── item │ │ ├── VZInspectorBizLogItem.h │ │ └── VZInspectorBizLogItem.m │ ├── keycommand │ │ ├── VZKeyCommands.h │ │ └── VZKeyCommands.m │ ├── manager │ │ ├── VZInspectorBizLogManager.h │ │ └── VZInspectorBizLogManager.m │ └── view │ │ ├── VZInspectorBizLogCell.h │ │ ├── VZInspectorBizLogCell.m │ │ ├── VZInspectorBizLogToolBarItem.h │ │ ├── VZInspectorBizLogToolBarItem.m │ │ ├── VZInspectorBizLogView.h │ │ ├── VZInspectorBizLogView.m │ │ ├── VZInspectorMaskView.h │ │ ├── VZInspectorMaskView.m │ │ ├── VZInspectorSearchBar.h │ │ ├── VZInspectorSearchBar.m │ │ ├── VZInspectorTagListView.h │ │ ├── VZInspectorTagListView.m │ │ ├── VZInspectorTagView.h │ │ └── VZInspectorTagView.m ├── log │ ├── VZInspectorLogView.h │ ├── VZInspectorLogView.m │ ├── VZLogInspector.h │ └── VZLogInspector.m ├── overview │ ├── VZInspectorOverview.h │ ├── VZInspectorOverview.m │ ├── VZInspectorPlotView.h │ ├── VZInspectorPlotView.m │ ├── VZOverviewInspector.h │ ├── VZOverviewInspector.m │ ├── controller │ │ ├── VZControllerStack.h │ │ └── VZControllerStack.m │ ├── device │ │ ├── VZDevice.h │ │ └── VZDevice.m │ ├── env │ │ ├── VZInspectorSettingView.h │ │ ├── VZInspectorSettingView.m │ │ ├── VZSettingInspector.h │ │ └── VZSettingInspector.m │ └── memory │ │ ├── VZMemoryInspector.h │ │ ├── VZMemoryInspector.m │ │ ├── VZMemoryInspectorOverView.h │ │ └── VZMemoryInspectorOverView.m └── toolbox │ ├── VZInspectorToolItem.h │ ├── VZInspectorToolItem.m │ ├── VZInspectorToolboxView.h │ ├── VZInspectorToolboxView.m │ ├── border │ ├── VZBorderInspector.h │ └── VZBorderInspector.m │ ├── colorPicker │ ├── VZColorDisplayView.h │ ├── VZColorDisplayView.m │ ├── VZColorPanelView.h │ ├── VZColorPanelView.m │ ├── VZColorPickerDefine.h │ ├── VZInspectorColorPickerView.h │ └── VZInspectorColorPickerView.m │ ├── crash │ ├── VZCrashInspector.h │ ├── VZCrashInspector.m │ ├── VZInspectorCrashRootView.h │ ├── VZInspectorCrashRootView.m │ ├── VZInspectorCrashView.h │ └── VZInspectorCrashView.m │ ├── framerate │ ├── VZFrameRateOverlay.h │ └── VZFrameRateOverlay.m │ ├── grid │ ├── UIWindow+VZInspector.h │ ├── UIWindow+VZInspector.m │ ├── VZInspectorGridView.h │ └── VZInspectorGridView.m │ ├── image │ ├── VZInspectorImageInfoView.h │ └── VZInspectorImageInfoView.m │ ├── location │ ├── CLLocationManager+FLFake.h │ ├── CLLocationManager+FLFake.m │ ├── FLFakeConfig.h │ ├── FLFakeConfig.m │ ├── VZInspectorLocationView.h │ └── VZInspectorLocationView.m │ ├── network │ ├── VZInspectorNetworkDetailView.h │ ├── VZInspectorNetworkDetailView.m │ ├── VZInspectorNetworkHistoryView.h │ ├── VZInspectorNetworkHistoryView.m │ ├── VZNetworkInspector.h │ ├── VZNetworkInspector.m │ ├── VZNetworkInspectorOverView.h │ ├── VZNetworkInspectorOverView.m │ ├── VZNetworkObserver.h │ ├── VZNetworkObserver.m │ ├── VZNetworkRecorder.h │ ├── VZNetworkRecorder.m │ ├── VZNetworkTransaction.h │ └── VZNetworkTransaction.m │ └── sandbox │ ├── VZInspectorSandBoxRootView.h │ ├── VZInspectorSandBoxRootView.m │ ├── VZInspectorSandBoxSubView.h │ └── VZInspectorSandBoxSubView.m ├── VZInspectorDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── VZInspectorDemo.xcscheme ├── VZInspectorDemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.mm └── main.m └── logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | wp 2 | # Xcode 3 | # 4 | build/ 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | xcuserdata 14 | *.xccheckout 15 | *.moved-aside 16 | DerivedData 17 | *.hmap 18 | *.ipa 19 | *.xcuserstate 20 | xcuserdata/ 21 | *.xccheckout 22 | contents.xcworkspacedata 23 | 24 | # CocoaPods 25 | # 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 29 | # 30 | Pods/* 31 | Pods 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode8.3 3 | branches: 4 | only: 5 | - master 6 | script: xcodebuild -project VZInspectorDemo.xcodeproj -scheme VZInspectorDemo -sdk iphonesimulator 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-2017 VZInspector (jayson.xu@foxmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![VZInspector](https://github.com/akaDealloc/VZInspector/blob/master/logo.png) 3 | 4 | # VZInspector 5 | 6 | [![Build Status](https://travis-ci.org/xta0/VZInspector.svg?branch=master)](http://cocoapods.org/pods/VZInspector) 7 | [![Version](https://img.shields.io/cocoapods/v/VZInspector.svg?style=flat)](http://cocoapods.org/pods/VZInspector) 8 | [![License](https://img.shields.io/cocoapods/l/VZInspector.svg?style=flat)](http://cocoapods.org/pods/VZInspector) 9 | [![Platform](https://img.shields.io/cocoapods/p/VZInspector.svg?style=flat)](http://cocoapods.org/pods/VZInspector) 10 | 11 | > This project is no longer being actively developed or maintained. 12 | 13 | 14 | ## 简介 15 | 16 | VZInspector 是一个给 iOS 开发者使用的 debug 工具,包含日志查询、取色、控件检查、视觉稿比对等功能,同时提供了丰富的接口方便自行定制。 17 | 18 | ## 接入 19 | 20 | ### 使用 Cocoapods 21 | 22 | ``` 23 | pod 'VZInspector' 24 | ``` 25 | 26 | Pod安装成功后,在`AppDelegate.m`中引入头文件: 27 | 28 | ```objc 29 | #import "VZInspector/VZInspector.h" 30 | ``` 31 | 32 | 在`AppDelegate.m`中配置`VZInspector`插件 33 | 34 | ```objc 35 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ 36 | 37 | //some code above... 38 | 39 | [VZInspector setClassPrefixName:@"VZ"]; 40 | [VZInspector setShouldHandleCrash:true]; 41 | [VZInspector setShouldHookNetworkRequest:true]; 42 | [VZInspector setLogNumbers:10]; 43 | [VZInspector showOnStatusBar]; 44 | 45 | //some code below 46 | } 47 | ``` 48 | 49 | ## 功能说明 50 | 51 | 这部分按照 VZInspector 界面上的功能区块,分别介绍 VZInspector 内置的功能以及可自定义的功能。 52 | 53 | ![](https://zos.alipayobjects.com/rmsportal/RPZQsqbWsOwTxWJOlmnu.png) 54 | 55 | ### 内存占用 56 | 57 | App 当前内存占用显示在 Status 顶部,折线显示内存占用变化趋势。 58 | 59 | 60 | 61 | ### Dashboard 62 | 63 | 这里显示一些常用信息,比如 uid、视图栈、特定 UserDefaults 的值等,默认显示设备信息和视图栈,可以通过以下代码自定义该区域内容。点击“R”按钮会重新获取该区域内容。 64 | 65 | ```c 66 | + (void)setupVZInspector { 67 | [VZInspector addObserveCallback:^NSString *{ 68 | //返回需要追加显示的信息 69 | }]; 70 | } 71 | 72 | ``` 73 | 74 | 75 | 76 | ### 自定义 77 | 78 | 在 Memory Usage 区域上面有一个自定义区域,供你放置一些开关,例如我们在这里做了环境切换、清理内存缓存的功能,环境切换功能深受测试同学喜欢。自定义示例如下: 79 | 80 | 81 | 82 | ```c 83 | //自定义 Dashboard 开关 84 | [VZInspector addDashboardSwitch:@"发布环境" Highlight:productEnv?:NO Callback:^{ 85 | //按钮点击动作 86 | }]; 87 | ``` 88 | 89 | ## Log 90 | 91 | Log 界面显示 NSLog 输出的信息,可以在不连接 Xcode 时直接查看日志,最新的日志在顶部显示。此外顶部提供了过滤功能;右下区域的三个按钮分别对应 `回到顶部`、`打开/关闭自动刷新` 和 `刷新` 操作。 92 | 93 | 94 | 95 | ### 自定义 96 | 97 | 顶部搜索框可以进行简单过滤,为了避免每次输入相同关键词,你可以用下面的代码添加关键词过滤按钮。 98 | 99 | ```c 100 | //设置 Log 过滤关键词 101 | [VZLogInspector sharedInstance].searchList = @[@"keyword1", @"keyword2"]; 102 | ``` 103 | 104 | 设置好的关键词会以按钮形式显示,点击即可显示相应关键词的过滤结果。 105 | 106 | 107 | 108 | ## Toolbox 109 | 110 | Toolbox 界面提供了一些常用小工具,例如网络日志查看、控件检查、帧率监测。开关类的工具在打开时会在右上角显示 `ON`。 111 | 112 | 113 | 114 | ### Logs 115 | 116 | Logs 用来实时查看网络请求的状态、返回等,需要自行配置网关信息,如下所示: 117 | 118 | ```c 119 | + (void)setupNetworkMonitorConfig 120 | { 121 | [VZInspector setShouldHookNetworkRequest:true]; 122 | 123 | [[VZNetworkInspector sharedInstance] addTransactionTitleFilter:^NSString *(VZNetworkTransaction *transaction) { 124 | if ([transaction.request.URL.host rangeOfString:@"YourGatewayKeyword"].location != NSNotFound) { 125 | NSString *operationType = [transaction.request valueForHTTPHeaderField:@"Operation-Type"]; 126 | if (operationType.length == 0) { 127 | NSData *bodyData = [transaction postBodyData]; 128 | NSString *body = [[NSString alloc] initWithData:bodyData encoding:NSUTF8StringEncoding]; 129 | 130 | NSString *parten = @"operationType=([a-zA-Z0-9.]*)"; 131 | NSRegularExpression *reg = [NSRegularExpression regularExpressionWithPattern:parten options:kNilOptions error:nil]; 132 | NSTextCheckingResult* match = [reg firstMatchInString:body options:kNilOptions range:NSMakeRange(0, [body length])]; 133 | if (match) { 134 | operationType = [body substringWithRange:[match rangeAtIndex:1]]; 135 | } 136 | } 137 | if (operationType.length > 0) { 138 | return operationType; 139 | } 140 | } 141 | return nil; 142 | }]; 143 | 144 | [VZNetworkInspector setIgnoreDelegateClasses:[NSSet setWithObjects:@"ClassesYouWantToIgnore", nil]]; 145 | } 146 | ``` 147 | 148 | 149 | 150 | ### Crash 151 | 152 | 可以捕获 App 的 Crash 日志,开启方法: 153 | 154 | ```c 155 | //打开 crash 捕获 156 | [VZInspector setShouldHandleCrash:YES]; 157 | ``` 158 | 159 | 160 | 161 | ### Sandbox 162 | 163 | 用来展示应用沙盒文件,对于文本和图片文件,点击可以预览。 164 | 165 | ### Grid 166 | 167 | 网格工具用来做视觉检查,比如简单的控件对齐、控件尺寸等。 168 | 169 | 170 | 171 | #### Border 172 | 173 | 边框检查工具能显示当前界面所有控件的边框,可以用来进行视觉检查。此外你可以设置类前缀关键词,比如“O2O”,这样就会将所有“O2O”开头的类的类名显示出来。 174 | 175 | ```c 176 | //自定义显示类名的控件类前缀 177 | [VZInspector setClassPrefixName:@"O2O"]; 178 | ``` 179 | 180 | 181 | 182 | ### Warning 183 | 184 | Warning 用来模拟内存警告,可以帮你验证 `didReceiveMemoryWarning` 里的逻辑,当打开的时候,可以在 “Memory Usage” 区域看到红色闪烁标识。 185 | 186 | 187 | 188 | ### Image 189 | 190 | Image 工具用于检查界面上的图片,比如查看图片尺寸,图片 URL。 191 | 192 | 193 | 194 | 工具栏的按钮从左到右依次为: 195 | - **返回** 196 | - **分享**,可以在手机上把当前选择的图片 AirDrop 到电脑上 197 | - **复制**,可以把选择的图片和描述复制到剪切板,再按 Ctrl+C 从模拟器复制出来 198 | - **切换**,点击切换是否开启选择模式,关闭选择模式来操作界面 199 | 200 | 选择图片后会把图片置顶显示,并显示出被裁剪的部分。 201 | 屏幕上方(或下方)显示图片和 View 的尺寸、scale、宽高比,图片帧数。另外 O2O 中额外增加了图片 URL 的显示。 202 | 203 | 204 | 205 | 如果点击的位置有多个重叠的图片,可以多次点击来切换选择的图片。 206 | 207 | ### Location 208 | 209 | Location 工具用来模拟经纬度,打开开关后输入经纬度即可。界面上也提供了一些常用城市的经纬度。 210 | 211 | 212 | 213 | ### FrameRate 214 | 215 | 帧率监测工具可以将帧率显示在状态栏上。注:模拟器无法精准检测帧率,仅在真机上有效。 216 | 217 | 218 | 219 | ### ColorPicker 220 | 221 | 提供屏幕取色的功能。 222 | - 按像素取值,并将颜色展示在下面控制板 223 | - 拖动底部的slider可以控制放大倍率(5 ~ 30倍) 224 | - 拖动取色器可以移动取色的位置,在取色器外滑动可以慢速移动,方便按像素取值移动 225 | 226 | 227 | 228 | 229 | 230 | ## Plugin 231 | 232 | 插件界面方便你在 VZInspector 中放置自己开发的插件,如下图所示。这部分完全是业务相关的工具,可以使用下面的代码进行自定义。 233 | 234 | 235 | 236 | ```c 237 | //添加自定义插件 238 | VZInspectorToolItem *scan = [VZInspectorToolItem itemWithName:@"scan" icon:icon callback:^{ 239 | //按钮点击动作 240 | }]; 241 | [VZInspector addToolItem:scan]; 242 | ``` 243 | 244 | # License 245 | 246 | VZInspector 基于 MIT License,更多信息查看:https://opensource.org/licenses/MIT 247 | 248 | # Contribution 249 | 250 | 欢迎任何建议 & Pull request。 251 | -------------------------------------------------------------------------------- /VZInspector.podspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pod::Spec.new do |s| 4 | 5 | s.name = "VZInspector" 6 | s.version = "0.1.8" 7 | s.summary = "an iOS app runtime debugger" 8 | s.homepage = "https://github.com/xta0/VZInspector" 9 | s.license = "MIT" 10 | s.author = { "xta0" => "xta0.me@gmail.com" } 11 | s.platform = :ios, "8.0" 12 | s.ios.deployment_target = "8.0" 13 | s.source = { :git => "https://github.com/xta0/VZInspector", :tag => "#{s.version}" } 14 | s.requires_arc = true 15 | s.framework = 'Foundation', 'UIKit', 'CoreGraphics', 'QuartzCore' 16 | s.source_files = 'VZInspector/**/*.{h,c,m,mm}' 17 | s.libraries = "z", "c++" 18 | s.xcconfig = { 19 | 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11', 20 | 'CLANG_CXX_LIBRARY' => 'libc++' 21 | } 22 | end 23 | -------------------------------------------------------------------------------- /VZInspector/VZDefine.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | #define fequal(a,b) (fabs((a) - (b)) < FLT_EPSILON) 8 | #define fequalzero(a) (fabs(a) < FLT_EPSILON) 9 | #define flessthan(a,b) (fabs(a) < fabs(b)+FLT_EPSILON) 10 | 11 | /** 12 | * 用一个24位的整数生成UIColor 13 | * 这个方法实现如下,只会返回不透明的颜色 14 | return [UIColor colorWithRed:((rgb & 0xFF0000) >> 16) / 255.0f 15 | green:((rgb & 0xFF00) >> 8) / 255.0f 16 | blue:((rgb & 0xFF)) / 255.0f 17 | alpha:1.0f]; 18 | * @param rgb 形如0xRRGGBB 19 | */ 20 | #define VZ_RGBA( rgb , a) [UIColor colorWithRed:((rgb & 0xFF0000) >> 16 ) / 255.0f green:((rgb & 0xFF00) >> 8)/255.0f blue:((rgb & 0xFF)) / 255.0f alpha:a ] 21 | #define VZ_RGB(rgb) VZ_RGBA(rgb ,1.0f ) 22 | 23 | #define VZ_INSPECTOR_MAIN_COLOR VZ_RGB(0xfd8023) 24 | 25 | 26 | #define screen_width [UIScreen mainScreen].bounds.size.width 27 | 28 | #define VZ_TextSizeFrame(text , fontSize) [text boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:fontSize]} context:nil].size 29 | 30 | #define vz_IsStringValid(_str) (_str && [_str isKindOfClass:[NSString class]] && ([_str length] > 0)) 31 | #define vz_IsArrayValid(_array) (_array && [_array isKindOfClass:[NSArray class]] && ([_array count] > 0)) 32 | #define vz_IsDictionaryValid(__dic) (__dic && [__dic isKindOfClass:[NSDictionary class]] && ([__dic count] > 0)) 33 | 34 | #define kOnePix (1.0f/[UIScreen mainScreen].scale) 35 | 36 | -------------------------------------------------------------------------------- /VZInspector/VZInspector.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import "VZInspectController.h" 7 | #import "VZInspectorToolItem.h" 8 | 9 | @interface VZInspector : NSObject 10 | 11 | /* 12 | *在状态栏显示入口 13 | */ 14 | + (void)showOnStatusBar; 15 | + (BOOL)isShow; 16 | /* 17 | *打开inspector 18 | */ 19 | + (void)show; 20 | /* 21 | *关闭inspector 22 | */ 23 | + (void)hide; 24 | /* 25 | *设置业务类代码前缀 26 | */ 27 | + (void)setClassPrefixName:(NSString* )name; 28 | /* 29 | *是否要记录crash日志 30 | */ 31 | + (void)setShouldHandleCrash:(BOOL)b; 32 | /** 33 | *是否要hook网络请求 34 | */ 35 | + (void)setShouldHookNetworkRequest:(BOOL)b; 36 | /** 37 | * 设置log数量限制 38 | */ 39 | + (void)setLogNumbers:(NSUInteger)num; 40 | /* 41 | *注入要观察的全局信息 42 | */ 43 | + (void)addObserveCallback:(NSString* (^)(void)) callback; 44 | /** 45 | * 注入自定义插件 46 | */ 47 | + (void)addToolItem:(VZInspectorToolItem *)toolItem; 48 | /* 49 | * 返回所有注册的自定义插件 50 | */ 51 | + (NSArray *)additionTools; 52 | 53 | @end 54 | 55 | 56 | @interface VZInspector(env) 57 | /** 58 | * 增加 Dashboard 头部开关 59 | */ 60 | + (void)addDashboardSwitch:(NSString* )type Highlight:(BOOL)highligh Callback:(void(^)(void))callback; 61 | 62 | 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /VZInspector/VZInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspector.h" 6 | #import "VZInspectorOverlay.h" 7 | #import "VZInspectorWindow.h" 8 | #import "VZCrashInspector.h" 9 | #import "VZOverviewInspector.h" 10 | #import "VZSettingInspector.h" 11 | #import "VZLogInspector.h" 12 | #import "VZNetworkObserver.h" 13 | #import "VZBorderInspector.h" 14 | #import "VZInspectorToolboxView.h" 15 | #import "VZDevice.h" 16 | 17 | 18 | @implementation VZInspector 19 | 20 | 21 | 22 | + (void)showOnStatusBar 23 | { 24 | //dispatch to the next runloop 25 | dispatch_async(dispatch_get_main_queue(), ^{ 26 | [VZInspectorOverlay show]; 27 | }); 28 | 29 | } 30 | 31 | + (BOOL)isShow 32 | { 33 | return ![VZInspectorWindow sharedInstance].hidden; 34 | } 35 | 36 | + (void)show 37 | { 38 | // NSData *data = [NSData dataWithContentsOfFile:@"/Users/lingwan/ios-phone-o2o-debug/VZInspector/aa.png"]; 39 | // NSUInteger len = [data length]; 40 | // Byte *byteData = (Byte*)malloc(len); 41 | // memcpy(byteData, [data bytes], len); 42 | // 43 | // for (int i=0; i 6 | 7 | @interface NSObject (VZInspector) 8 | 9 | /** 10 | for debugger use 11 | */ 12 | @property(nonatomic,strong) NSMutableArray* samplePoints; 13 | /** 14 | for debugger use 15 | */ 16 | - (void)vz_heartBeat; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /VZInspector/core/NSObject+VZInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "NSObject+VZInspector.h" 6 | #include 7 | 8 | 9 | @implementation NSObject (VZInspector) 10 | 11 | - (void)setSamplePoints:(NSMutableArray *)samplePoints 12 | { 13 | objc_setAssociatedObject(self, "samplePoints", samplePoints, OBJC_ASSOCIATION_RETAIN); 14 | } 15 | 16 | - (NSString*)samplePoints 17 | { 18 | return objc_getAssociatedObject(self, "samplePoints"); 19 | } 20 | 21 | - (void)vz_heartBeat 22 | { 23 | 24 | } 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @class VZInspectorToolboxView; 8 | 9 | @interface VZInspectController : UIViewController 10 | 11 | @property(nonatomic,strong,readonly) UIView* currentView; 12 | @property(nonatomic,assign,readonly) NSString* currentTab; 13 | 14 | @property(nonatomic,strong) VZInspectorToolboxView* toolboxView; 15 | @property(nonatomic,strong) VZInspectorToolboxView* pluginView; 16 | 17 | - (void)start; 18 | - (void)stop; 19 | - (BOOL)canTouchPassThrough:(CGPoint)pt; 20 | - (void)onClose; 21 | - (void)transitionToView:(UIView *)view; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorAssert.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #ifndef VZInspector_VZInspectorAssert_h 6 | #define VZInspector_VZInspectorAssert_h 7 | 8 | #include 9 | 10 | 11 | 12 | static inline BOOL vz_isMainThread(){return 0 != pthread_main_np();}; 13 | #define VZIPAssert(...) Assert(__VA_ARGS__) 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorOverlay.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZInspectorOverlay : UIWindow 8 | 9 | +(instancetype)sharedInstance; 10 | +(void)show; 11 | +(void)hide; 12 | 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorOverlay.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorOverlay.h" 6 | #import "VZInspector.h" 7 | #import "VZInspectorResource.h" 8 | 9 | 10 | @implementation VZInspectorOverlay 11 | 12 | + (instancetype)sharedInstance 13 | { 14 | static VZInspectorOverlay* instance = nil; 15 | static dispatch_once_t onceToken; 16 | dispatch_once(&onceToken, ^{ 17 | 18 | int x = [UIScreen mainScreen].bounds.size.width > 320 ? 250 :180 ; 19 | instance = [[VZInspectorOverlay alloc]initWithFrame:CGRectMake(x, 0, 60, 20)]; 20 | }); 21 | return instance; 22 | 23 | } 24 | 25 | +(void)show 26 | { 27 | VZInspectorOverlay* o = [self sharedInstance]; 28 | o.tag = 100; 29 | o.windowLevel = UIWindowLevelStatusBar+1; 30 | o.hidden = NO; 31 | } 32 | +(void)hide 33 | { 34 | for (UIWindow* window in [UIApplication sharedApplication].windows) { 35 | if ([window isKindOfClass:[VZInspectorOverlay class]]) { 36 | window.hidden = YES; 37 | break; 38 | } 39 | } 40 | } 41 | - (id)initWithFrame:(CGRect)frame 42 | { 43 | self = [super initWithFrame:frame]; 44 | 45 | if ( self ) 46 | { 47 | self.backgroundColor = [UIColor clearColor]; 48 | 49 | UIImageView* imgv = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; 50 | imgv.contentMode = UIViewContentModeScaleAspectFit; 51 | imgv.image = [VZInspectorResource eye]; 52 | imgv.userInteractionEnabled = true; 53 | [imgv addGestureRecognizer:[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(onSelfClicked:)]]; 54 | [self addSubview:imgv]; 55 | 56 | } 57 | return self; 58 | } 59 | 60 | - (void)onSelfClicked:(UIButton* )sender 61 | { 62 | if([VZInspector isShow]) 63 | [VZInspector hide]; 64 | else 65 | [VZInspector show]; 66 | } 67 | 68 | - (void)becomeKeyWindow 69 | { 70 | //fix keywindow problem: 71 | //UIActionSheet在close后回重置keywindow,防止自己被设成keywindow 72 | [[[UIApplication sharedApplication].delegate window] makeKeyWindow]; 73 | } 74 | 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorResource.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | #define VZ_IMAGE(BYTE_ARRAY) [VZInspectorResource imageWithBytes:BYTE_ARRAY length:sizeof(BYTE_ARRAY)] 9 | #define VZ_IMAGE_SCALE(BYTE_ARRAY, SCALE) [VZInspectorResource imageWithBytes:BYTE_ARRAY length:sizeof(BYTE_ARRAY) scale:SCALE] 10 | 11 | @interface VZInspectorResource : NSObject 12 | 13 | + (UIImage *)imageWithBytes:(const uint8_t *)bytes length:(size_t)length; 14 | + (UIImage *)imageWithBytes:(const uint8_t *)bytes length:(size_t)length scale:(CGFloat)scale; 15 | 16 | + (UIImage *)logo; 17 | 18 | + (UIImage *)eye; 19 | 20 | + (UIImage *)grid; 21 | 22 | + (UIImage *)sandbox; 23 | 24 | + (UIImage *)network_logs; 25 | 26 | + (UIImage *)crash; 27 | 28 | + (UIImage *)memoryWarning; 29 | 30 | + (UIImage *)border; 31 | 32 | + (UIImage *)viewClass; 33 | 34 | + (UIImage *)image; 35 | 36 | + (UIImage *)location; 37 | 38 | + (UIImage *)frameRate; 39 | 40 | + (UIImage *)behaviorLog; 41 | 42 | + (UIImage *)asyncIcon; 43 | 44 | + (UIImage *)colorPickerIcon; 45 | 46 | + (UIImage *)tipIcon; 47 | 48 | + (UIImage *)schemeManagerIcon; 49 | 50 | + (UIImage *)scanIcon; 51 | 52 | + (UIImage *)pluginIcon; 53 | 54 | + (UIImage *)searchBarIcon; 55 | 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorTimer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | 8 | extern const NSString* kVZTimerReadCallbackString; 9 | extern const NSString* kVZTimerWriteCallbackString; 10 | extern const NSString* kVZTimerStartCallbackString; 11 | extern const NSString* kVZTimerStopCallbackString; 12 | 13 | typedef void(^vz_inspectorTimerReadCallback)(void); 14 | typedef void(^vz_inspectorTimerWriteCallback)(void) ; 15 | 16 | @interface VZInspectorTimer : NSObject 17 | 18 | @property(nonatomic,copy) vz_inspectorTimerReadCallback readCallback; 19 | @property(nonatomic,copy) vz_inspectorTimerWriteCallback writeCallback; 20 | 21 | + (instancetype)sharedInstance; 22 | 23 | - (void)startTimer; 24 | 25 | - (void)stopTimer; 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorTimer.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorTimer.h" 6 | #import "VZMemoryInspector.h" 7 | #import "VZNetworkInspector.h" 8 | #import "NSObject+VZInspector.h" 9 | 10 | 11 | NSString const* kVZTimerReadCallbackString = @"kVZTimerReadCallbackString"; 12 | NSString const* kVZTimerWriteCallbackString = @"kVZTimerWriteCallbackString"; 13 | NSString const* kVZTimerStartCallbackString = @"kVZTimerStartCallbackString"; 14 | NSString const* kVZTimerStopCallbackString = @"kVZTimerStopCallbackString"; 15 | 16 | @interface NSTimer(VZInspector) 17 | +(NSTimer* )scheduledTimerWithTimeInterval:(NSTimeInterval)ti block:(void(^)(void))block userInfo:(id)userInfo repeats:(BOOL)repeat; 18 | @end 19 | 20 | @implementation NSTimer(VZInspector) 21 | 22 | + (NSTimer* )scheduledTimerWithTimeInterval:(NSTimeInterval)ti block:(void (^)(void))block userInfo:(id)userInfo repeats:(BOOL)repeat 23 | { 24 | return [NSTimer scheduledTimerWithTimeInterval:ti target:self selector:@selector(onTimerFired:) userInfo:[block copy] repeats:repeat]; 25 | } 26 | 27 | + (void)onTimerFired:(NSTimer* )timer 28 | { 29 | void(^block)(void) = timer.userInfo; 30 | 31 | if (block) { 32 | block(); 33 | } 34 | } 35 | 36 | @end 37 | 38 | @interface VZInspectorTimer() 39 | 40 | @property(nonatomic,strong)NSTimer* readTimer; 41 | @property(nonatomic,strong)NSTimer* writeTimer; 42 | 43 | @end 44 | 45 | @implementation VZInspectorTimer 46 | { 47 | 48 | } 49 | 50 | + (instancetype)sharedInstance 51 | { 52 | static VZInspectorTimer* instance = nil; 53 | static dispatch_once_t onceToken; 54 | dispatch_once(&onceToken, ^{ 55 | instance = [VZInspectorTimer new]; 56 | }); 57 | return instance; 58 | } 59 | 60 | 61 | - (void)startTimer 62 | { 63 | [[NSNotificationCenter defaultCenter] postNotificationName:(NSString* const)kVZTimerStartCallbackString object:nil]; 64 | 65 | __weak typeof(self) weakSelf = self; 66 | [VZInspectorTimer sharedInstance].readTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 block:^{ 67 | 68 | //timer 69 | [weakSelf handleRead]; 70 | 71 | } userInfo:nil repeats:YES]; 72 | 73 | [[NSRunLoop currentRunLoop] addTimer:[VZInspectorTimer sharedInstance].readTimer forMode:NSRunLoopCommonModes]; 74 | 75 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 76 | 77 | [VZInspectorTimer sharedInstance].writeTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 block:^{ 78 | 79 | //timer 80 | [weakSelf handleWrite]; 81 | 82 | } userInfo:nil repeats:YES]; 83 | 84 | [[NSRunLoop currentRunLoop] addTimer:[VZInspectorTimer sharedInstance].writeTimer forMode:NSRunLoopCommonModes]; 85 | 86 | }); 87 | } 88 | 89 | - (void)stopTimer 90 | { 91 | [[NSNotificationCenter defaultCenter] postNotificationName:(NSString* const)kVZTimerStopCallbackString object:nil]; 92 | 93 | [[VZInspectorTimer sharedInstance].readTimer invalidate]; 94 | [[VZInspectorTimer sharedInstance].writeTimer invalidate]; 95 | [VZInspectorTimer sharedInstance].readTimer = nil; 96 | [VZInspectorTimer sharedInstance].writeTimer = nil; 97 | } 98 | 99 | - (void)handleRead 100 | { 101 | [[NSNotificationCenter defaultCenter] postNotificationName:(NSString* const)kVZTimerReadCallbackString object:nil]; 102 | 103 | if (self.readCallback) { 104 | self.readCallback(); 105 | } 106 | } 107 | 108 | - (void)handleWrite 109 | { 110 | [[NSNotificationCenter defaultCenter] postNotificationName:(NSString* const)kVZTimerWriteCallbackString object:nil]; 111 | 112 | if (self.writeCallback) { 113 | self.writeCallback(); 114 | } 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorUtility.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | @class VZNetworkTransaction; 9 | 10 | @interface VZInspectorUtility : NSObject 11 | 12 | + (NSDictionary *)dictionaryFromQuery:(NSString *)query; 13 | 14 | + (NSString *)prettyJSONStringFromData:(NSData *)data; 15 | 16 | + (NSString *)prettyJSONStringFromObject:(id)jsonObject; 17 | 18 | + (NSString *)prettyStringFromRequestBodyForTransaction:(VZNetworkTransaction *)transaction; 19 | 20 | + (NSString *)prettyStringFromResponseBodyForTransaction:(VZNetworkTransaction *)transaction; 21 | 22 | + (NSString *)timestampStringFromRequestDate:(NSDate *)date; 23 | 24 | + (NSString *)stringFromRequestDuration:(NSTimeInterval)duration; 25 | 26 | + (NSString *)statusCodeStringFromURLResponse:(NSURLResponse *)response; 27 | 28 | + (NSData *)inflatedDataFromCompressedData:(NSData *)compressedData; 29 | 30 | + (NSString *)stringFormatFromDate:(NSDate *)date; 31 | 32 | + (UIColor* )themeColor; 33 | 34 | + (UIColor* )blueColor; 35 | 36 | + (UILabel *)simpleLabel:(CGRect)frame f:(int)size tc:(UIColor *)color t:(NSString *)text; 37 | 38 | + (UILabel *)simpleBorderLabel:(CGRect)frame f:(int)size tc:(UIColor *)color t:(NSString *)text; 39 | 40 | + (UIButton *)simpleButton:(CGRect)frame f:(int)size tc:(UIColor *)color t:( NSString *)text; 41 | 42 | + (UIImage *)imageWithColor:(UIColor *)color; 43 | 44 | + (BOOL)validateRegularExpression:(NSString *)pattern string:(NSString *)string; 45 | 46 | + (BOOL)isNumber:(NSString *)string; 47 | 48 | + (UIWindow *)mainWindow ; 49 | 50 | @end 51 | 52 | extern void VZSwapClassMethods(Class cls, SEL original, SEL replacement); 53 | 54 | extern void VZSwapInstanceMethods(Class cls, SEL original, SEL replacement); 55 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZInspectorView : UIView 8 | 9 | @property(nonatomic,weak) UIViewController* parentViewController; 10 | 11 | - (id)initWithFrame:(CGRect)frame parentViewController:(UIViewController* )controller; 12 | - (void)update; 13 | - (void)pop; 14 | - (BOOL)canTouchPassThrough:(CGPoint)pt; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @implementation VZInspectorView 8 | 9 | - (id)initWithFrame:(CGRect)frame parentViewController:(UIViewController* )controller 10 | { 11 | self.parentViewController = controller; 12 | return [self initWithFrame:frame]; 13 | } 14 | 15 | - (id)initWithFrame:(CGRect)frame 16 | { 17 | self = [super initWithFrame:frame]; 18 | 19 | if (self) { 20 | 21 | } 22 | return self; 23 | } 24 | 25 | - (void)update 26 | { 27 | //noop 28 | } 29 | 30 | - (void)pop 31 | { 32 | #pragma clang diagnostic push 33 | #pragma clang diagnostic ignored "-Wundeclared-selector" 34 | [self.parentViewController performSelector:@selector(onBack)]; 35 | #pragma clang diagnostic pop 36 | } 37 | 38 | - (BOOL)canTouchPassThrough:(CGPoint)pt 39 | { 40 | return NO; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | #import "VZInspectController.h" 8 | 9 | @interface VZInspectorWindow : UIWindow 10 | 11 | 12 | +(instancetype)sharedInstance; 13 | +(VZInspectController *)sharedController; 14 | 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /VZInspector/core/VZInspectorWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorWindow.h" 6 | #import "VZInspectController.h" 7 | 8 | @interface VZInspectorWindow() 9 | 10 | @property(nonatomic,strong) VZInspectController* debuggerVC; 11 | 12 | @end 13 | 14 | @implementation VZInspectorWindow 15 | 16 | 17 | + (instancetype)sharedInstance 18 | { 19 | static VZInspectorWindow* instance = nil; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | instance = [[VZInspectorWindow alloc]init]; 23 | }); 24 | return instance; 25 | 26 | } 27 | 28 | + (VZInspectController *)sharedController { 29 | return [[self sharedInstance] debuggerVC]; 30 | } 31 | 32 | - (id)init 33 | { 34 | CGRect screenBound = [UIScreen mainScreen].bounds; 35 | self = [super initWithFrame:screenBound]; 36 | if (self) 37 | { 38 | self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6f]; 39 | //self.backgroundColor = [UIColor colorWithWhite:0.2 alpha:0.5]; 40 | self.hidden = YES; 41 | self.windowLevel = UIWindowLevelStatusBar + 200; 42 | self.userInteractionEnabled = NO; 43 | 44 | self.debuggerVC = [VZInspectController new]; 45 | self.rootViewController = self.debuggerVC; 46 | [self addSubview:self.debuggerVC.view]; 47 | 48 | } 49 | return self; 50 | } 51 | 52 | - (void)setHidden:(BOOL)hidden 53 | { 54 | [super setHidden:hidden]; 55 | 56 | if ( self.hidden ) 57 | { 58 | [self.debuggerVC stop]; 59 | } 60 | else 61 | { 62 | [self.debuggerVC start]; 63 | } 64 | } 65 | 66 | 67 | - (UIView* )hitTest:(CGPoint)point withEvent:(UIEvent *)event 68 | { 69 | CGPoint pt = [self convertPoint:point toView:self.debuggerVC.view]; 70 | 71 | if (self.debuggerVC.presentedViewController) { 72 | for (long i = self.subviews.count - 1; i >= 0; i --) { 73 | UIView *subview = self.subviews[i]; 74 | CGPoint convertedPoint = [subview convertPoint:point fromView:self]; 75 | UIView *hited = [subview hitTest:convertedPoint withEvent:event]; 76 | if (hited) { 77 | return hited; 78 | } 79 | } 80 | } 81 | if ([self.debuggerVC canTouchPassThrough:pt]) { 82 | return [super hitTest:point withEvent:event]; 83 | } 84 | else 85 | return [self.debuggerVC.view hitTest:point withEvent:event]; 86 | // return self.debuggerVC.view; 87 | } 88 | 89 | 90 | 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /VZInspector/core/item/VZInspectorBizLogItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZInspectorBizLogItem : NSObject 8 | 9 | @property (nonatomic, assign) float itemHeight; 10 | 11 | @property (nonatomic, assign) Class cellClass; 12 | 13 | @property (nonatomic, strong) NSIndexPath *indexPath; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /VZInspector/core/item/VZInspectorBizLogItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorBizLogItem.h" 6 | 7 | @implementation VZInspectorBizLogItem 8 | 9 | - (void)encodeWithCoder:(NSCoder *)aCoder{ 10 | 11 | [aCoder encodeObject:self.indexPath forKey:@"indexPath"]; 12 | [aCoder encodeObject:@(self.itemHeight) forKey:@"itemHeight"]; 13 | [aCoder encodeObject:self.cellClass forKey:@"cellClass"]; 14 | 15 | } 16 | 17 | - (id)initWithCoder:(NSCoder *)aDecoder 18 | { 19 | self = [self init]; 20 | if (self){ 21 | 22 | self.indexPath = [aDecoder decodeObjectForKey:@"indexPath"]; 23 | self.itemHeight = ((NSNumber*)[aDecoder decodeObjectForKey:@"itemHeight"]).floatValue; 24 | self.cellClass = [aDecoder decodeObjectForKey:@"cellClass"]; 25 | } 26 | return self; 27 | } 28 | 29 | - (id)copyWithZone:(NSZone *)zone 30 | { 31 | VZInspectorBizLogItem* item = [[self class] allocWithZone:zone]; 32 | item.indexPath = self.indexPath; 33 | item.itemHeight = self.itemHeight; 34 | item.cellClass = self.cellClass; 35 | return item; 36 | } 37 | 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /VZInspector/core/keycommand/VZKeyCommands.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface VZKeyCommands : NSObject 13 | 14 | + (instancetype)sharedInstance; 15 | 16 | /** 17 | * Register a single-press keyboard command. 18 | */ 19 | - (void)registerKeyCommandWithInput:(NSString *)input 20 | modifierFlags:(UIKeyModifierFlags)flags 21 | action:(void (^)(UIKeyCommand *command))block; 22 | 23 | /** 24 | * Unregister a single-press keyboard command. 25 | */ 26 | - (void)unregisterKeyCommandWithInput:(NSString *)input 27 | modifierFlags:(UIKeyModifierFlags)flags; 28 | 29 | /** 30 | * Check if a single-press command is registered. 31 | */ 32 | - (BOOL)isKeyCommandRegisteredForInput:(NSString *)input 33 | modifierFlags:(UIKeyModifierFlags)flags; 34 | 35 | /** 36 | * Register a double-press keyboard command. 37 | */ 38 | - (void)registerDoublePressKeyCommandWithInput:(NSString *)input 39 | modifierFlags:(UIKeyModifierFlags)flags 40 | action:(void (^)(UIKeyCommand *command))block; 41 | 42 | /** 43 | * Unregister a double-press keyboard command. 44 | */ 45 | - (void)unregisterDoublePressKeyCommandWithInput:(NSString *)input 46 | modifierFlags:(UIKeyModifierFlags)flags; 47 | 48 | /** 49 | * Check if a double-press command is registered. 50 | */ 51 | - (BOOL)isDoublePressKeyCommandRegisteredForInput:(NSString *)input 52 | modifierFlags:(UIKeyModifierFlags)flags; 53 | 54 | @end -------------------------------------------------------------------------------- /VZInspector/core/manager/VZInspectorBizLogManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import "VZInspectorBizLogView.h" 7 | 8 | @interface VZInspectorBizLogManager : NSObject 9 | 10 | @property (nonatomic, strong) VZInspectorBizLogView *logView; 11 | 12 | 13 | + (instancetype)sharedInstance ; 14 | 15 | - (void)show; 16 | 17 | - (void)hide; 18 | 19 | - (void)toggle; 20 | 21 | - (void)onClickClearButton; 22 | 23 | - (void)onClickCancleButton; 24 | 25 | - (BOOL)isShowing; 26 | @end 27 | -------------------------------------------------------------------------------- /VZInspector/core/manager/VZInspectorBizLogManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorBizLogManager.h" 6 | 7 | @interface VZInspectorBizLogManager() 8 | 9 | @property (nonatomic, assign) CGRect logViewFrameBeforeDragging; 10 | 11 | @end 12 | 13 | @implementation VZInspectorBizLogManager{ 14 | BOOL _isShowing; 15 | } 16 | 17 | + (instancetype)sharedInstance { 18 | static VZInspectorBizLogManager *_manager = nil; 19 | static dispatch_once_t onceToken; 20 | dispatch_once(&onceToken, ^{ 21 | _manager = [[VZInspectorBizLogManager alloc] init]; 22 | }); 23 | return _manager; 24 | } 25 | 26 | 27 | - (void)toggle{ 28 | if(_isShowing){ 29 | [self hide]; 30 | }else { 31 | [self show]; 32 | } 33 | } 34 | 35 | - (void)show{ 36 | if(!_isShowing){ 37 | if(self.logView){ 38 | self.logView.delegate = self; 39 | [[UIApplication sharedApplication].keyWindow addSubview:self.logView]; 40 | } 41 | } 42 | _isShowing = YES; 43 | } 44 | 45 | - (void)hide{ 46 | if(self.logView){ 47 | [self.logView removeFromSuperview]; 48 | self.logView.delegate = nil; 49 | } 50 | _isShowing = NO; 51 | } 52 | 53 | - (BOOL)isShowing{ 54 | return _isShowing; 55 | } 56 | 57 | - (void)onClickCancleButton{ 58 | //subclass todo 59 | [self hide]; 60 | } 61 | 62 | - (void)onClickClearButton{ 63 | // subclass todo 64 | } 65 | 66 | - (void)dragLogViewPanGesture:(UIPanGestureRecognizer *)pan { 67 | if(self.logView){ 68 | switch (pan.state) { 69 | case UIGestureRecognizerStateBegan: 70 | self.logViewFrameBeforeDragging = self.logView.frame; 71 | [self updateToolbarPostionWithDragGesture:pan]; 72 | break; 73 | 74 | case UIGestureRecognizerStateChanged: 75 | case UIGestureRecognizerStateEnded: 76 | [self updateToolbarPostionWithDragGesture:pan]; 77 | break; 78 | 79 | default: 80 | break; 81 | } 82 | } 83 | } 84 | 85 | 86 | - (void)updateToolbarPostionWithDragGesture:(UIPanGestureRecognizer *)pan { 87 | 88 | if(self.logView){ 89 | UIView *superView = self.logView.superview; 90 | CGPoint translation = [pan translationInView:superView]; 91 | CGRect newlogViewFrame = self.logViewFrameBeforeDragging; 92 | newlogViewFrame.origin.y += translation.y; 93 | 94 | CGFloat maxY = CGRectGetMaxY(superView.bounds) - newlogViewFrame.size.height; 95 | if (newlogViewFrame.origin.y < 0.0) { 96 | newlogViewFrame.origin.y = 0.0; 97 | } else if (newlogViewFrame.origin.y > maxY) { 98 | newlogViewFrame.origin.y = maxY; 99 | } 100 | 101 | self.logView.frame = newlogViewFrame; 102 | } 103 | } 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorBizLogCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import "VZInspectorBizLogItem.h" 7 | 8 | @interface VZInspectorBizLogCell : UITableViewCell 9 | 10 | /** 11 | * cell的index 12 | */ 13 | @property (nonatomic,strong) NSIndexPath* indexPath; 14 | /** 15 | * cell绑定的item数据 16 | */ 17 | @property (nonatomic,strong) VZInspectorBizLogItem* item; 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorBizLogCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorBizLogCell.h" 6 | 7 | @implementation VZInspectorBizLogCell 8 | 9 | 10 | - (void)setItem:(VZInspectorBizLogItem *)item{ 11 | _item = item; 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorBizLogToolBarItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | @interface VZInspectorBizLogToolBarItem : NSObject 9 | 10 | @property(nonatomic, strong)NSString *normalTitle; 11 | 12 | @property(nonatomic, strong)NSString *selectedTitle; 13 | 14 | @property(nonatomic, strong)UIColor *normalTitleColor; 15 | 16 | @property(nonatomic, strong)UIColor *selectedTitleColor; 17 | 18 | @property(nonatomic, strong)UIColor *normalBackgroundColor; 19 | 20 | @property(nonatomic, strong)UIColor *selectedbackgroundColor; 21 | 22 | @property(nonatomic, strong)UIColor *normalBorderColor; 23 | 24 | @property(nonatomic, strong)UIColor *selectedBorderColor; 25 | 26 | @property(nonatomic, assign)BOOL isSelected; 27 | 28 | //这里不会有其他其他状态的改变,只会把当前点击的返回 29 | @property(nonatomic, assign)BOOL onlyClick; 30 | 31 | @property(nonatomic, assign) NSUInteger type; 32 | 33 | // groupId 为0 表示互不影响,可以共存, 如果groupId > 0 ,则按groupId分组,分组内的东西互斥 34 | @property(nonatomic, assign) NSUInteger groupId; 35 | 36 | + (VZInspectorBizLogToolBarItem *)normalToolBarItemWithNormalTitle:(NSString *)normalTitle selectedTitle:(NSString *)selectedTitle type:(NSUInteger)type isSelected:(BOOL)isSelected groupId:(NSUInteger)groupId; 37 | 38 | + (VZInspectorBizLogToolBarItem *)normalToolBarItemWithNormalTitle:(NSString *)normalTitle selectedTitle:(NSString *)selectedTitle type:(NSUInteger)type isSelected:(BOOL)isSelected; 39 | 40 | + (VZInspectorBizLogToolBarItem *)normalToolBarItemWithNormalTitle:(NSString *)normalTitle selectedTitle:(NSString *)selectedTitle type:(NSUInteger)type onlyClick:(BOOL)onlyClick; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorBizLogToolBarItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorBizLogToolBarItem.h" 6 | #import "VZDefine.h" 7 | 8 | @implementation VZInspectorBizLogToolBarItem 9 | 10 | - (instancetype)init{ 11 | if(self = [super init]){ 12 | _normalTitleColor = VZ_RGB(0x000000); 13 | _normalBackgroundColor = VZ_RGB(0xffffff); 14 | _normalBorderColor = VZ_RGB(0xbdc8d0); 15 | _selectedBorderColor = VZ_INSPECTOR_MAIN_COLOR; 16 | _groupId = 0; 17 | } 18 | return self; 19 | } 20 | 21 | + (VZInspectorBizLogToolBarItem *)normalToolBarItemWithNormalTitle:(NSString *)normalTitle selectedTitle:(NSString *)selectedTitle type:(NSUInteger)type isSelected:(BOOL)isSelected groupId:(NSUInteger)groupId{ 22 | VZInspectorBizLogToolBarItem *item = [VZInspectorBizLogToolBarItem new]; 23 | item.normalTitle = normalTitle; 24 | item.selectedTitle = selectedTitle; 25 | item.isSelected = isSelected; 26 | item.groupId = groupId; 27 | item.type = type; 28 | 29 | return item; 30 | } 31 | 32 | + (VZInspectorBizLogToolBarItem *)normalToolBarItemWithNormalTitle:(NSString *)normalTitle selectedTitle:(NSString *)selectedTitle type:(NSUInteger)type isSelected:(BOOL)isSelected{ 33 | return [self.class normalToolBarItemWithNormalTitle:normalTitle selectedTitle:selectedTitle type:type isSelected:isSelected groupId:0]; 34 | } 35 | 36 | + (VZInspectorBizLogToolBarItem *)normalToolBarItemWithNormalTitle:(NSString *)normalTitle selectedTitle:(NSString *)selectedTitle type:(NSUInteger)type onlyClick:(BOOL)onlyClick{ 37 | VZInspectorBizLogToolBarItem *item = [self.class normalToolBarItemWithNormalTitle:normalTitle selectedTitle:selectedTitle type:type isSelected:NO groupId:0]; 38 | item.onlyClick = onlyClick; 39 | return item; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorBizLogView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import "VZInspectorBizLogItem.h" 7 | #import "VZInspectorBizLogToolBarItem.h" 8 | #import "VZInspectorTagListView.h" 9 | #import "VZInspectorSearchBar.h" 10 | 11 | @protocol VZInspectorBizLogViewDelegate 12 | 13 | @optional 14 | - (void)onClickCancleButton; 15 | - (void)onClickClearButton; 16 | 17 | @end 18 | 19 | @interface VZInspectorBizLogView : UIView 20 | 21 | @property (nonatomic , weak) id delegate; 22 | 23 | @property (nonatomic, strong) NSMutableArray *items; 24 | 25 | @property (nonatomic, strong) UITableView *tableView; 26 | 27 | @property (nonatomic, strong) UIView *headerView; 28 | 29 | @property (nonatomic, strong) UILabel *dragView; 30 | 31 | @property (nonatomic, strong) VZInspectorSearchBar *searchView; 32 | 33 | @property (nonatomic, strong) VZInspectorTagListView *tagListView; 34 | 35 | @property (nonatomic, strong) UIView *searchBarBackgroundView; 36 | 37 | @property (nonatomic, strong) NSString *title; 38 | 39 | @property (nonatomic, strong) NSString *leftButtonTitle; 40 | 41 | @property (nonatomic, strong) NSString *rightButtonTitle; 42 | 43 | @property (nonatomic, assign) BOOL hasSearchBar; 44 | 45 | @property (nonatomic,strong) NSArray *toolBarItems; 46 | 47 | @property (nonatomic, strong)VZInspectorTagViewTap tagViewTapListener; 48 | 49 | - (void)reloadDatas; 50 | 51 | - (void)setToolBarHidden:(BOOL)hidden; 52 | 53 | - (VZInspectorBizLogItem *)itemForCellAtIndexPath:(NSIndexPath *)indexPath; 54 | 55 | - (void)addDragTagGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer; 56 | 57 | -(void)textFieldTextDidChange:(UITextField *)textField; 58 | 59 | - (void)leftButtonClick; 60 | 61 | - (void)rightButtonClick; 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorMaskView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @protocol VZInspectorMaskViewCancleDelegate 8 | 9 | @optional 10 | 11 | - (void)cancleMaskView; 12 | 13 | @end 14 | 15 | @interface VZInspectorMaskView : UIView 16 | 17 | @property (nonatomic, strong) UIView *rootView; 18 | 19 | @property (nonatomic, weak) id delegate; 20 | 21 | 22 | /** 23 | * 背景view 24 | */ 25 | @property (nonatomic, strong) UIView *backgroudView; 26 | 27 | /** 28 | * 内容view 29 | */ 30 | @property (nonatomic, strong) UIView *contentView; 31 | 32 | 33 | /** 34 | * 点击内容区外的区域取消蒙层 ,默认为NO; 35 | */ 36 | @property (nonatomic, assign) BOOL canceledOnTouchOutside; 37 | 38 | 39 | - (instancetype)initWithFrame:(CGRect)frame rootView:(UIView *)rootView ; 40 | 41 | 42 | /** 43 | * 蒙层是否正在显示 44 | * 45 | */ 46 | - (BOOL)isShowing; 47 | 48 | /** 49 | * 隐藏蒙层 50 | */ 51 | - (void)hideMaskView; 52 | 53 | /** 54 | * 显示蒙层 55 | */ 56 | - (void)showMaskView; 57 | 58 | /** 59 | * 开始布局蒙层里面的视图 60 | */ 61 | - (void)layoutMaskviews; 62 | 63 | - (void)removeFromSuperview; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorMaskView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorMaskView.h" 6 | #import "VZDefine.h" 7 | #import 8 | 9 | @implementation VZInspectorMaskView{ 10 | BOOL _showing; 11 | CGRect _contentFrame; 12 | CGRect _rootFrame ; 13 | 14 | } 15 | 16 | - (instancetype)initWithFrame:(CGRect)frame rootView:(UIView *)rootView{ 17 | if(self = [super init]){ 18 | _contentFrame = frame; 19 | _rootFrame = rootView.frame; 20 | _contentView = [[UIView alloc]initWithFrame:frame]; 21 | _backgroudView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, _rootFrame.size.width, _rootFrame.size.height)]; 22 | _backgroudView.backgroundColor = VZ_RGBA(0x000000, 0.68); 23 | 24 | _contentView.center = CGPointMake(_rootFrame.size.width/2, _rootFrame.size.height/2); 25 | _contentFrame = _contentView.frame; 26 | 27 | [_backgroudView addSubview:_contentView]; 28 | 29 | [_backgroudView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapBackgroundView)]]; 30 | 31 | _rootView = rootView; 32 | _showing = NO; 33 | _canceledOnTouchOutside = NO; 34 | [self layoutMaskviews]; 35 | } 36 | 37 | return self; 38 | } 39 | 40 | - (void)setCanceledOnTouchOutside:(BOOL)canceledOnTouchOutside{ 41 | if(canceledOnTouchOutside){ 42 | _backgroudView.userInteractionEnabled = YES; 43 | }else{ 44 | _backgroudView.userInteractionEnabled = NO; 45 | } 46 | _canceledOnTouchOutside = canceledOnTouchOutside; 47 | } 48 | 49 | - (void)setBackgroudView:(UIView *)backgroudView{ 50 | if(_backgroudView){ 51 | [_contentView removeFromSuperview]; 52 | [_backgroudView removeFromSuperview]; 53 | } 54 | _backgroudView = backgroudView; 55 | [_backgroudView addSubview:_contentView]; 56 | } 57 | 58 | - (void)tapBackgroundView{ 59 | if(_canceledOnTouchOutside){ 60 | if([self.delegate respondsToSelector:@selector(cancleMaskView)]){ 61 | [self.delegate cancleMaskView]; 62 | } 63 | } 64 | } 65 | 66 | - (void)hideMaskView{ 67 | if (_rootView && _backgroudView) { 68 | 69 | [UIView animateWithDuration:0.3 animations:^{ 70 | self->_backgroudView.alpha = 0.0; 71 | 72 | } completion:^(BOOL finished) { 73 | [self->_backgroudView removeFromSuperview]; 74 | self->_showing = NO; 75 | }]; 76 | } 77 | } 78 | 79 | - (void)showMaskView{ 80 | if(_rootView && _backgroudView){ 81 | [_backgroudView removeFromSuperview]; 82 | _backgroudView.alpha = 1; 83 | [_rootView addSubview:_backgroudView]; 84 | [_rootView bringSubviewToFront:_backgroudView]; 85 | _showing = YES; 86 | } 87 | } 88 | 89 | - (void)removeFromSuperview{ 90 | if(_rootView && _backgroudView){ 91 | [_backgroudView removeFromSuperview]; 92 | _showing = NO; 93 | } 94 | } 95 | 96 | - (BOOL)isShowing{ 97 | return _showing; 98 | } 99 | 100 | - (void)layoutMaskviews{ 101 | //subClass todo 102 | } 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorSearchBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZInspectorSearchBar : UITextField 8 | 9 | @property (nonatomic, assign) UIEdgeInsets edgeInsets; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorSearchBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorSearchBar.h" 6 | 7 | @implementation VZInspectorSearchBar 8 | 9 | - (CGRect)textRectForBounds:(CGRect)bounds 10 | { 11 | return [super textRectForBounds:UIEdgeInsetsInsetRect(bounds, _edgeInsets)]; 12 | } 13 | 14 | - (CGRect)editingRectForBounds:(CGRect)bounds 15 | { 16 | return [super editingRectForBounds:UIEdgeInsetsInsetRect(bounds, _edgeInsets)]; 17 | } 18 | 19 | - (CGRect)leftViewRectForBounds:(CGRect)bounds{ 20 | return [super leftViewRectForBounds:UIEdgeInsetsInsetRect(bounds, _edgeInsets)]; 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorTagListView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TagListView.h 3 | // TagObjc 4 | // 5 | // Created by Javi Pulido on 16/7/15. 6 | // Copyright (c) 2015 Javi Pulido. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "VZInspectorBizLogToolBarItem.h" 11 | 12 | @class VZInspectorTagView; 13 | 14 | typedef void (^VZInspectorTagViewTap)(NSArray *); 15 | 16 | 17 | @interface VZInspectorTagListView : UIView 18 | 19 | @property (nonatomic) UIColor *textColor; 20 | @property (nonatomic) UIColor *tagBackgroundColor; 21 | @property (nonatomic) CGFloat cornerRadius; 22 | @property (nonatomic) CGFloat borderWidth; 23 | @property (nonatomic) UIColor *borderColor; 24 | @property (nonatomic) CGFloat paddingY; 25 | @property (nonatomic) CGFloat paddingX; 26 | @property (nonatomic) CGFloat marginY; 27 | @property (nonatomic) CGFloat marginX; 28 | @property (nonatomic) UIFont *textFont; 29 | 30 | 31 | @property (nonatomic) CGFloat tagViewHeight; 32 | @property (nonatomic ,assign)CGFloat frameHeight; 33 | @property (nonatomic) NSMutableArray *tagViews; 34 | @property (nonatomic) int rows; 35 | 36 | @property (nonatomic ,strong)VZInspectorTagViewTap tagViewTap; 37 | 38 | - (void)addTagItems:(NSArray *)tagItems; 39 | - (void)removeTag:(NSString *)title; 40 | - (void)removeAllTags; 41 | 42 | - (void)setSelectedTagView:(VZInspectorTagView *)tagView; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorTagView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TagView.h 3 | // TagObjc 4 | // 5 | // Created by Javi Pulido on 16/7/15. 6 | // Copyright (c) 2015 Javi Pulido. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "VZInspectorBizLogToolBarItem.h" 11 | 12 | @interface VZInspectorTagView : UIButton 13 | 14 | - (instancetype) initWithTitle:(NSString *)title; 15 | 16 | @property (nonatomic) CGFloat cornerRadius; 17 | @property (nonatomic) CGFloat borderWidth; 18 | @property (nonatomic) UIColor *borderColor; 19 | @property (nonatomic) UIColor *textColor; 20 | @property (nonatomic) CGFloat paddingY; 21 | @property (nonatomic) CGFloat paddingX; 22 | @property (nonatomic) UIFont *textFont; 23 | 24 | @property (nonatomic , strong) VZInspectorBizLogToolBarItem *item; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /VZInspector/core/view/VZInspectorTagView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TagView.m 3 | // TagObjc 4 | // 5 | // Created by Javi Pulido on 16/7/15. 6 | // Copyright (c) 2015 Javi Pulido. All rights reserved. 7 | // 8 | 9 | #import "VZInspectorTagView.h" 10 | 11 | 12 | 13 | @implementation VZInspectorTagView{ 14 | BOOL _hasCalculateSize; 15 | CGSize _textCalculateSize; 16 | } 17 | 18 | @synthesize textColor =_textColor; 19 | @synthesize textFont = _textFont; 20 | 21 | - (instancetype) initWithTitle:(NSString *)title { 22 | self = [super init]; 23 | if(self) { 24 | _hasCalculateSize = NO; 25 | [self setTitle:title forState:UIControlStateNormal]; 26 | CGSize intrinsicSize = [self intrinsicContentSize]; 27 | self.frame = CGRectMake(0, 0, intrinsicSize.width, intrinsicSize.height); 28 | } 29 | return self; 30 | } 31 | 32 | - (CGSize) intrinsicContentSize { 33 | 34 | if(_hasCalculateSize){ 35 | return _textCalculateSize; 36 | } 37 | 38 | 39 | CGSize size = [self.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: self.titleLabel.font}]; 40 | 41 | size.height = self.titleLabel.font.pointSize + self.paddingY * 2; 42 | size.width += self.paddingX * 2; 43 | 44 | _hasCalculateSize = YES; 45 | _textCalculateSize = size; 46 | return size; 47 | } 48 | 49 | # pragma mark - Getters 50 | 51 | - (UIColor *)textColor { 52 | if(!self.textColor) { 53 | self.textColor = [UIColor blackColor]; 54 | } 55 | return self.textColor; 56 | } 57 | 58 | - (UIFont *)textFont { 59 | if(!self.textFont) { 60 | self.textFont = [UIFont systemFontOfSize:12]; 61 | } 62 | return self.textFont; 63 | } 64 | 65 | # pragma mark - Setters 66 | 67 | - (void)setCornerRadius:(CGFloat)cornerRadius { 68 | _cornerRadius = cornerRadius; 69 | self.layer.cornerRadius = cornerRadius; 70 | self.layer.masksToBounds = self.cornerRadius > 0; 71 | } 72 | 73 | - (void)setBorderWidth:(CGFloat)borderWidth { 74 | _borderWidth = borderWidth; 75 | self.layer.borderWidth = borderWidth; 76 | 77 | } 78 | 79 | - (void)setBorderColor:(UIColor *)borderColor { 80 | _borderColor = borderColor; 81 | self.layer.borderColor = borderColor.CGColor; 82 | } 83 | 84 | - (void)setTextColor:(UIColor *)textColor { 85 | _textColor = textColor; 86 | [self setTitleColor:textColor forState:UIControlStateNormal]; 87 | } 88 | 89 | - (void)setPaddingY:(CGFloat)paddingY { 90 | _paddingY = paddingY; 91 | UIEdgeInsets insets = [self titleEdgeInsets]; 92 | insets.top = paddingY; 93 | insets.bottom = paddingY; 94 | [self setTitleEdgeInsets:insets]; 95 | } 96 | 97 | - (void)setPaddingX:(CGFloat)paddingX { 98 | _paddingX = paddingX; 99 | UIEdgeInsets insets = [self titleEdgeInsets]; 100 | insets.left = paddingX; 101 | insets.right = paddingX; 102 | [self setTitleEdgeInsets:insets]; 103 | } 104 | 105 | - (void)setTextFont:(UIFont *)textFont { 106 | _textFont = textFont; 107 | _hasCalculateSize = NO; 108 | [self.titleLabel setFont:textFont]; 109 | } 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /VZInspector/log/VZInspectorLogView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @interface VZInspectorLogView : VZInspectorView 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /VZInspector/log/VZLogInspector.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | #define kVZDefaultNumberOfLogs 20 8 | 9 | @class VZLogInspectorEntity; 10 | @protocol VZLogInspectorDelegate 11 | 12 | - (void)logMessage:(VZLogInspectorEntity *)message; 13 | 14 | @end 15 | 16 | @interface VZLogInspectorEntity:NSObject 17 | 18 | @property (nonatomic, strong) NSDate *date; 19 | @property (nonatomic, copy) NSString *sender; 20 | @property (nonatomic, copy) NSString *messageText; 21 | @property (nonatomic, assign) long long messageID; 22 | @property (nonatomic, assign) NSUInteger level; 23 | @end 24 | 25 | @interface VZLogInspector : NSObject 26 | 27 | @property(nonatomic,copy) NSArray *searchList; 28 | 29 | + (instancetype) sharedInstance; 30 | 31 | @property (nonatomic, strong) NSMutableArray *observers; 32 | 33 | @property (nonatomic, assign) id delegate; 34 | 35 | + (void)setNumberOfLogs:(NSUInteger)num; 36 | 37 | + (NSArray* )logs; 38 | 39 | + (NSAttributedString* )logsString:(NSString *)searchkey; 40 | 41 | +(NSAttributedString *)formatLog:(VZLogInspectorEntity *)entity searchkey:(NSString *)searchKey; 42 | 43 | + (void)start; 44 | 45 | + (void)stop; 46 | 47 | - (void)addObserver:(id)observer; 48 | 49 | - (void)removeObserver:(id)observer; 50 | @end 51 | -------------------------------------------------------------------------------- /VZInspector/overview/VZInspectorOverview.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | 8 | @interface VZInspectorOverview : VZInspectorView 9 | 10 | @property(nonatomic,assign) BOOL memoryWarning; 11 | 12 | - (void)updateGlobalInfo; 13 | 14 | - (void)startTimer; 15 | 16 | - (void)stopTimer; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /VZInspector/overview/VZInspectorOverview.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorOverview.h" 6 | #import "VZMemoryInspectorOverView.h" 7 | #import "VZMemoryInspector.h" 8 | #import "VZInspectorTimer.h" 9 | #import "VZOverviewInspector.h" 10 | #import "NSObject+VZInspector.h" 11 | #import "VZBorderInspector.h" 12 | #import "VZInspectorSettingView.h" 13 | #import "VZControllerStack.h" 14 | 15 | #import 16 | 17 | @interface VZInspectorOverview() 18 | 19 | @property(nonatomic,strong) VZMemoryInspectorOverView* memoryView; 20 | @property(nonatomic, strong) VZInspectorSettingView* settingView; 21 | @property(nonatomic,strong) UITextView* infoView; 22 | @property(nonatomic,strong) UIButton* refreshBtn; 23 | 24 | @end 25 | 26 | 27 | @implementation VZInspectorOverview 28 | 29 | - (id)initWithFrame:(CGRect)frame 30 | { 31 | self = [super initWithFrame:frame]; 32 | if (self) { 33 | CGFloat width = self.frame.size.width; 34 | 35 | //envView 36 | CGRect envFrame; 37 | envFrame.origin = CGPointMake(0, 10); 38 | envFrame.size.width = width; 39 | envFrame.size.height = [VZInspectorSettingView heightForEnvButtons]; 40 | _settingView = [[VZInspectorSettingView alloc]initWithFrame:CGRectInset(envFrame, 10, 0) parentViewController:self.parentViewController]; 41 | [self addSubview:_settingView]; 42 | 43 | //total memory 44 | CGRect memoryFrame; 45 | memoryFrame.origin = CGPointMake(0, CGRectGetMaxY(_settingView.frame) + 10); 46 | memoryFrame.size.width = width; 47 | memoryFrame.size.height = 65; 48 | 49 | _memoryView = [[VZMemoryInspectorOverView alloc] initWithFrame:memoryFrame]; 50 | [self addSubview:_memoryView]; 51 | 52 | //infoView 53 | CGRect infoFrame; 54 | infoFrame.origin = CGPointMake(0, CGRectGetMaxY(_memoryView.frame) - 1); 55 | infoFrame.size.width = width; 56 | infoFrame.size.height = frame.size.height - infoFrame.origin.y; 57 | 58 | _infoView = [[UITextView alloc] initWithFrame:CGRectInset(infoFrame, 10, 10)]; 59 | _infoView.font = [UIFont fontWithName:@"Courier-Bold" size:14]; 60 | _infoView.textColor = [UIColor orangeColor]; 61 | _infoView.indicatorStyle = 0; 62 | _infoView.editable = NO; 63 | _infoView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 64 | _infoView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6f]; 65 | [self addSubview:_infoView]; 66 | 67 | _refreshBtn = [[UIButton alloc]initWithFrame:CGRectMake(CGRectGetMaxX(_infoView.frame) - 54, CGRectGetMaxY(_infoView.frame)-54, 44, 44)]; 68 | _refreshBtn.layer.cornerRadius = 22; 69 | _refreshBtn.layer.masksToBounds = true; 70 | _refreshBtn.layer.borderColor = [UIColor grayColor].CGColor; 71 | _refreshBtn.layer.borderWidth = 2.0f; 72 | [_refreshBtn setTitle:@"R" forState:UIControlStateNormal]; 73 | [_refreshBtn setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; 74 | [_refreshBtn addTarget:self action:@selector(updateGlobalInfo) forControlEvents:UIControlEventTouchUpInside]; 75 | [self addSubview:_refreshBtn]; 76 | 77 | [self updateGlobalInfo]; 78 | 79 | //start timer 80 | __weak typeof(self) weakSelf = self; 81 | [VZInspectorTimer sharedInstance].readCallback = ^{ 82 | [weakSelf handleRead]; 83 | }; 84 | 85 | [VZInspectorTimer sharedInstance].writeCallback = ^{ 86 | [[NSNotificationCenter defaultCenter] postNotificationName:(NSString* const)kVZTimerWriteCallbackString object:nil]; 87 | [weakSelf handleWrite]; 88 | }; 89 | } 90 | 91 | return self; 92 | } 93 | 94 | - (void)dealloc 95 | { 96 | [[VZInspectorTimer sharedInstance] stopTimer]; 97 | } 98 | 99 | - (void)updateGlobalInfo 100 | { 101 | NSMutableString *text = [NSMutableString new]; 102 | for (vz_overview_callback callback in [VZOverviewInspector sharedInstance].observingCallbacks) { 103 | [text appendString:callback()]; 104 | [text appendString:@"\n\n"]; 105 | } 106 | [text appendFormat:@"Controller Stacks:\n%@", [VZControllerStack controllerStack]]; 107 | _infoView.text = text; 108 | } 109 | 110 | - (void)startTimer 111 | { 112 | [[VZInspectorTimer sharedInstance] startTimer]; 113 | } 114 | 115 | - (void)stopTimer 116 | { 117 | [[VZInspectorTimer sharedInstance] stopTimer]; 118 | } 119 | 120 | 121 | - (void)handleRead 122 | { 123 | [self.memoryView handleRead]; 124 | // [self.cpuView handleRead]; 125 | // [self.httpView handleRead]; 126 | 127 | if (self.memoryWarning) { 128 | 129 | if (self.memoryView.backgroundColor == [[UIColor redColor] colorWithAlphaComponent:0.6f]) { 130 | self.memoryView.backgroundColor = [UIColor clearColor]; 131 | } 132 | else 133 | self.memoryView.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.6f]; 134 | 135 | [VZMemoryInspector performLowMemoryWarning]; 136 | 137 | } 138 | else 139 | { 140 | self.memoryView.backgroundColor = [UIColor clearColor]; 141 | } 142 | 143 | } 144 | - (void)handleWrite 145 | { 146 | [self.memoryView handleWrite]; 147 | // [self.cpuView handleWrite]; 148 | // [self.httpView handleWrite]; 149 | } 150 | 151 | 152 | - (void)close:(id)sender 153 | { 154 | #pragma clang diagnostic push 155 | #pragma clang diagnostic ignored "-Wundeclared-selector" 156 | [self.parentViewController performSelector:@selector(onClose)]; 157 | #pragma clang pop 158 | } 159 | 160 | 161 | 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /VZInspector/overview/VZInspectorPlotView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZInspectorPlotView : UIView 8 | 9 | @property (nonatomic, assign) BOOL fill; 10 | @property (nonatomic, assign) BOOL border; 11 | @property (nonatomic, assign) CGFloat lineScale; 12 | @property (nonatomic, retain) UIColor * lineColor; 13 | @property (nonatomic, assign) CGFloat lineWidth; 14 | @property (nonatomic, assign) CGFloat lowerBound; 15 | @property (nonatomic, assign) CGFloat upperBound; 16 | @property (nonatomic, assign) NSUInteger capacity; 17 | @property (nonatomic, retain) NSArray * plots; 18 | @property (nonatomic, assign) CGFloat dot; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /VZInspector/overview/VZInspectorPlotView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorPlotView.h" 6 | 7 | @implementation VZInspectorPlotView 8 | 9 | - (id)initWithFrame:(CGRect)frame 10 | { 11 | self = [super initWithFrame:frame]; 12 | if (self) 13 | { 14 | self.backgroundColor = [UIColor clearColor]; 15 | 16 | self.fill = YES; 17 | self.border = YES; 18 | self.lineScale = 0.8f; 19 | self.lineColor = [UIColor whiteColor]; 20 | self.lineWidth = 2.0f; 21 | self.lowerBound = 0.0f; 22 | self.upperBound = 1.0f; 23 | self.capacity = 50; 24 | } 25 | return self; 26 | } 27 | 28 | - (void)dealloc 29 | { 30 | _lineColor = nil; 31 | _plots = nil; 32 | } 33 | 34 | - (void)drawRect:(CGRect)rect 35 | { 36 | [super drawRect:rect]; 37 | 38 | CGContextRef context = UIGraphicsGetCurrentContext(); 39 | if ( context ) 40 | { 41 | CGContextClearRect( context, self.bounds ); 42 | 43 | if ( self.fill ) 44 | { 45 | CGRect bound = CGRectInset( self.bounds, 4.0f, 2.0f ); 46 | CGPoint baseLine; 47 | baseLine.x = bound.origin.x; 48 | baseLine.y = bound.origin.y + bound.size.height; 49 | 50 | UIBezierPath * pathLines = [UIBezierPath bezierPath]; 51 | [pathLines moveToPoint:baseLine]; 52 | 53 | NSUInteger step = 0; 54 | 55 | for ( NSNumber * value in [_plots copy] ) 56 | { 57 | CGFloat v = value.floatValue; 58 | 59 | if ( v < _lowerBound ) 60 | { 61 | v = _lowerBound; 62 | } 63 | else if ( v > _upperBound ) 64 | { 65 | v = _upperBound; 66 | } 67 | 68 | CGFloat f = (v - _lowerBound) / (_upperBound - _lowerBound) * _lineScale; 69 | CGPoint p = CGPointMake( baseLine.x, baseLine.y - bound.size.height * f ); 70 | [pathLines addLineToPoint:p]; 71 | 72 | baseLine.x += bound.size.width / _capacity; 73 | 74 | step += 1; 75 | if ( step >= _capacity ) 76 | break; 77 | } 78 | 79 | [self.lineColor set]; 80 | 81 | [pathLines addLineToPoint:baseLine]; 82 | // [pathLines fill]; 83 | [pathLines fillWithBlendMode:kCGBlendModeXOR alpha:0.6f]; 84 | } 85 | 86 | if ( self.border ) 87 | { 88 | CGRect bound = CGRectInset( self.bounds, 4.0f, 2.0f ); 89 | CGPoint baseLine; 90 | baseLine.x = bound.origin.x; 91 | baseLine.y = bound.origin.y + bound.size.height; 92 | 93 | CGContextMoveToPoint( context, baseLine.x, baseLine.y ); 94 | 95 | NSUInteger step = 0; 96 | 97 | for ( NSNumber * value in [_plots copy] ) 98 | { 99 | CGFloat v = value.floatValue; 100 | 101 | if ( v < _lowerBound ) 102 | { 103 | v = _lowerBound; 104 | } 105 | else if ( v > _upperBound ) 106 | { 107 | v = _upperBound; 108 | } 109 | 110 | CGFloat f = (v - _lowerBound) / (_upperBound - _lowerBound) * _lineScale; 111 | CGPoint p = CGPointMake( baseLine.x, baseLine.y - bound.size.height * f ); 112 | 113 | CGContextAddLineToPoint( context, p.x, p.y ); 114 | 115 | // if (v == _upperBound) { 116 | // [[UIColor redColor] set]; 117 | // [@"top" drawAtPoint:p withFont:[UIFont systemFontOfSize:13]]; 118 | // } 119 | CGContextSetStrokeColorWithColor( context, self.lineColor.CGColor ); 120 | CGContextSetLineWidth( context, self.lineWidth ); 121 | CGContextSetLineCap( context, kCGLineCapRound ); 122 | CGContextSetLineJoin( context, kCGLineJoinRound ); 123 | CGContextStrokePath( context ); 124 | 125 | CGContextMoveToPoint( context, p.x, p.y ); 126 | baseLine.x += bound.size.width / _capacity; 127 | 128 | step += 1; 129 | if ( step >= _capacity ) 130 | break; 131 | } 132 | } 133 | } 134 | } 135 | 136 | 137 | @end 138 | -------------------------------------------------------------------------------- /VZInspector/overview/VZOverviewInspector.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | 8 | typedef NSString*(^vz_overview_callback)(void); 9 | @interface VZOverviewInspector : NSObject 10 | 11 | + (VZOverviewInspector* )sharedInstance; 12 | 13 | @property(nonatomic,copy) NSMutableArray *observingCallbacks; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /VZInspector/overview/VZOverviewInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZOverviewInspector.h" 6 | 7 | 8 | @interface VZOverviewInspector() 9 | 10 | @end 11 | 12 | @implementation VZOverviewInspector 13 | 14 | - (instancetype)init { 15 | if (self = [super init]) { 16 | _observingCallbacks = [NSMutableArray array]; 17 | } 18 | return self; 19 | } 20 | 21 | + (VZOverviewInspector* )sharedInstance 22 | { 23 | static VZOverviewInspector* instance = nil; 24 | 25 | static dispatch_once_t onceToken; 26 | dispatch_once(&onceToken, ^{ 27 | instance = [VZOverviewInspector new]; 28 | }); 29 | 30 | return instance; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /VZInspector/overview/controller/VZControllerStack.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZControllerStack : NSObject 8 | 9 | + (NSString *)controllerStack; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /VZInspector/overview/controller/VZControllerStack.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import "VZControllerStack.h" 7 | 8 | @implementation VZControllerStack 9 | 10 | + (NSString *)controllerStack 11 | { 12 | UIViewController *vc = [[[UIApplication sharedApplication] keyWindow] rootViewController]; 13 | return [self controllerStackWithController:vc indent:0]; 14 | } 15 | 16 | + (NSString *)controllerStackWithController:(UIViewController *)vc indent:(int)indent 17 | { 18 | if (!vc) { 19 | return @""; 20 | } 21 | NSMutableString *mutableResult = [NSMutableString string]; 22 | for (int i = 0; i < indent - 1; i ++) { 23 | [mutableResult appendString:@" |"]; 24 | } 25 | [mutableResult appendString:indent == 0 ? @"" : vc.presentingViewController.presentedViewController == vc ? @" +" : @" |"]; 26 | [mutableResult appendString:[self descriptionForVc:vc]]; 27 | indent += 1; 28 | for (UIViewController *childVc in vc.childViewControllers) { 29 | [mutableResult appendString:[self controllerStackWithController:childVc indent:indent]]; 30 | } 31 | if (vc.presentedViewController.presentingViewController == vc) { 32 | [mutableResult appendString:[self controllerStackWithController:vc.presentedViewController indent:indent]]; 33 | } 34 | return mutableResult; 35 | } 36 | 37 | + (NSString *)descriptionForVc:(UIViewController *)vc 38 | { 39 | int state = [[vc valueForKey:@"_appearState"] intValue]; 40 | NSString *appearState = nil; 41 | switch (state) { 42 | case 0: 43 | appearState = @"disappeared"; 44 | break; 45 | case 1: 46 | appearState = @"will appear"; 47 | break; 48 | case 2: 49 | appearState = @"appeared"; 50 | break; 51 | default: 52 | appearState = @""; 53 | break; 54 | } 55 | 56 | return [NSString stringWithFormat:@"<%@ %@>\n", vc.class, vc.isViewLoaded ? appearState : @"not loaded"]; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /VZInspector/overview/device/VZDevice.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZDevice : NSObject 8 | 9 | + (NSString *)systemVersion; 10 | + (NSString *)systemName; 11 | + (NSString *)name; 12 | + (NSString *)model; 13 | + (NSString *)locationAuth; 14 | + (NSString *)uuid; 15 | 16 | + (NSString *)networkType; 17 | + (NSArray *)infoArray; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /VZInspector/overview/env/VZInspectorSettingView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @interface VZInspectorSettingView : VZInspectorView 8 | 9 | + (CGFloat)heightForEnvButtons; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /VZInspector/overview/env/VZInspectorSettingView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #include 6 | #import "VZInspectorSettingView.h" 7 | #import "VZSettingInspector.h" 8 | 9 | 10 | @implementation VZInspectorSettingView 11 | 12 | #define cellHeight 40 13 | #define cellColCount 4 14 | 15 | - (id)initWithFrame:(CGRect)frame 16 | { 17 | self = [super initWithFrame:frame]; 18 | if (self) { 19 | 20 | NSArray* btns = [VZSettingInspector currentAPIEnvButtons]; 21 | int w = CGRectGetWidth(frame)/cellColCount; 22 | 23 | for (int i=0; i 6 | 7 | typedef void(^vz_api_env_callback)(void); 8 | typedef void(^vz_api_env_switch_callback)(void); 9 | 10 | @interface VZSettingInspector : NSObject 11 | 12 | + (VZSettingInspector* )sharedInstance; 13 | + (void)addAPIEnvButtonWithName:(NSString* )type Selected:(BOOL)selected Callback:(vz_api_env_callback)callback; 14 | + (void)addAPIEnvSwitchWithName:(NSString* )type Selected:(BOOL)selected Callback:(vz_api_env_switch_callback)callback; 15 | + (NSArray* )currentAPIEnvButtons; 16 | + (NSArray* )currentAPIEnvSwitches; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /VZInspector/overview/env/VZSettingInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZSettingInspector.h" 6 | 7 | @implementation VZSettingInspector 8 | { 9 | NSMutableArray* _btns; 10 | NSMutableArray* _switches; 11 | } 12 | 13 | + (VZSettingInspector* )sharedInstance 14 | { 15 | static VZSettingInspector* instance = nil; 16 | 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | instance = [VZSettingInspector new]; 20 | }); 21 | 22 | return instance; 23 | } 24 | 25 | - (id)init 26 | { 27 | self = [super init]; 28 | 29 | if (self) { 30 | _btns = [[NSMutableArray alloc]initWithCapacity:3]; 31 | _switches = [[NSMutableArray alloc]initWithCapacity:3]; 32 | 33 | } 34 | return self; 35 | } 36 | 37 | + (NSArray* )currentAPIEnvButtons 38 | { 39 | return [[VZSettingInspector sharedInstance] -> _btns copy]; 40 | } 41 | 42 | + (NSArray* )currentAPIEnvSwitches 43 | { 44 | return [[VZSettingInspector sharedInstance] -> _switches copy]; 45 | } 46 | 47 | + (void)addAPIEnvButtonWithName:(NSString* )type Selected:(BOOL)selected Callback:(vz_api_env_callback)callback{ 48 | 49 | if (type && callback) { 50 | [[VZSettingInspector sharedInstance] -> _btns addObject:@{type:@[callback,@(selected)]}]; 51 | } 52 | 53 | } 54 | 55 | + (void)addAPIEnvSwitchWithName:(NSString *)type Selected:(BOOL)selected Callback:(vz_api_env_switch_callback)callback{ 56 | 57 | if (type && callback) { 58 | [[VZSettingInspector sharedInstance] -> _switches addObject:@{type:@[callback,@(selected)]}]; 59 | } 60 | 61 | } 62 | 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /VZInspector/overview/memory/VZMemoryInspector.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZMemoryInspector : NSObject 8 | 9 | + (instancetype)sharedInstance; 10 | 11 | #pragma mark- Memory monitor 12 | 13 | /* 14 | * The number of bytes in memory that used 15 | **/ 16 | + (unsigned long long)bytesOfUsedMemory; 17 | 18 | /** 19 | * The number of bytes in memory that are free. 20 | */ 21 | + (unsigned long long)bytesOfFreeMemory; 22 | 23 | /** 24 | * The total number of bytes of memory. 25 | */ 26 | + (unsigned long long)bytesOfTotalMemory; 27 | /** 28 | * Simulate low memory warning 29 | * notice : _performMemoryWarning is private api 30 | */ 31 | + (void)performLowMemoryWarning; 32 | /** 33 | * The number of bytes free on disk. 34 | */ 35 | + (unsigned long long)bytesOfFreeDiskSpace; 36 | /** 37 | * The total number of bytes of disk space. 38 | */ 39 | + (unsigned long long)bytesOfTotalDiskSpace; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /VZInspector/overview/memory/VZMemoryInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZMemoryInspector.h" 6 | #include 7 | #include 8 | #include 9 | #import "NSObject+VZInspector.h" 10 | 11 | @interface VZMemoryInspector() 12 | { 13 | dispatch_queue_t _lock; 14 | } 15 | 16 | @end 17 | 18 | @implementation VZMemoryInspector 19 | 20 | 21 | + (instancetype)sharedInstance 22 | { 23 | static VZMemoryInspector* instance; 24 | static dispatch_once_t onceToken; 25 | dispatch_once(&onceToken, ^{ 26 | instance = [VZMemoryInspector new]; 27 | }); 28 | return instance; 29 | } 30 | 31 | static vm_size_t sPageSize = 0; 32 | static vm_statistics_data_t sVMStats; 33 | 34 | 35 | - (id)init 36 | { 37 | self = [super init]; 38 | 39 | if (self) 40 | { 41 | _lock = dispatch_queue_create( "com.ETMemoryMonitor.taskQueue", nil ); 42 | 43 | } 44 | 45 | return self; 46 | } 47 | - (void)dealloc 48 | { 49 | #if !OS_OBJECT_USE_OBJC 50 | dispatch_release(_lock); 51 | #endif 52 | } 53 | 54 | 55 | //for internal use 56 | + (BOOL)updateHostStatistics { 57 | mach_port_t host_port = mach_host_self(); 58 | mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t); 59 | host_page_size(host_port, &sPageSize); 60 | return (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&sVMStats, &host_size) 61 | == KERN_SUCCESS); 62 | } 63 | /* 64 | * The number of bytes in memory that used 65 | **/ 66 | 67 | + (unsigned long long)bytesOfUsedMemory 68 | { 69 | /* 70 | * stackoverflow.com/questions/7989864/watching-memory-usage-in-ios 71 | */ 72 | // struct task_basic_info info; 73 | // mach_msg_type_number_t size = sizeof(info); 74 | // kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size); 75 | // return (kerr == KERN_SUCCESS) ? info.resident_size : 0; // size in bytes 76 | 77 | struct mstats stat = mstats(); 78 | 79 | return stat.bytes_used; 80 | 81 | } 82 | 83 | /** 84 | * The number of bytes in memory that are free. 85 | */ 86 | + (unsigned long long)bytesOfFreeMemory 87 | { 88 | return NSRealMemoryAvailable(); 89 | } 90 | /** 91 | * The total number of bytes of memory. 92 | */ 93 | + (unsigned long long)bytesOfTotalMemory 94 | { 95 | [self updateHostStatistics]; 96 | 97 | unsigned long long free_count = (unsigned long long)sVMStats.free_count; 98 | unsigned long long active_count = (unsigned long long)sVMStats.active_count; 99 | unsigned long long inactive_count = (unsigned long long)sVMStats.inactive_count; 100 | unsigned long long wire_count = (unsigned long long)sVMStats.wire_count; 101 | unsigned long long pageSize = (unsigned long long)sPageSize; 102 | 103 | unsigned long long mem_free = (free_count + active_count + inactive_count + wire_count) * pageSize; 104 | 105 | 106 | return mem_free; 107 | } 108 | + (void)performLowMemoryWarning 109 | { 110 | #ifdef DEBUG 111 | SEL memoryWarningSel = NSSelectorFromString(@"_performMemoryWarning"); 112 | if ([[UIApplication sharedApplication] respondsToSelector:memoryWarningSel]) { 113 | 114 | #pragma clang diagnostic push 115 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 116 | [[UIApplication sharedApplication] performSelector:memoryWarningSel]; 117 | #pragma clang diagnostic pop 118 | 119 | NSLog(@"[%@]-->memory warning",self.class); 120 | 121 | } else { 122 | // UIApplication no loger responds to _performMemoryWarning 123 | exit(1); 124 | } 125 | #endif 126 | } 127 | 128 | /** 129 | * The number of bytes free on disk. 130 | */ 131 | + (unsigned long long)bytesOfFreeDiskSpace 132 | { 133 | return 0; 134 | } 135 | /** 136 | * The total number of bytes of disk space. 137 | */ 138 | + (unsigned long long)bytesOfTotalDiskSpace 139 | { 140 | return 0; 141 | } 142 | 143 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 144 | #pragma mark - for debugger use 145 | 146 | - (void)vz_heartBeat 147 | { 148 | if (self.samplePoints == nil) 149 | self.samplePoints = [NSMutableArray new]; 150 | 151 | [self.samplePoints addObject:[NSNumber numberWithUnsignedLongLong:[[self class] bytesOfUsedMemory]]]; 152 | 153 | //keep last 50 points 154 | if ( [self.samplePoints count] > 50 ) 155 | { 156 | NSRange range; 157 | range.location = 0; 158 | range.length = [self.samplePoints count] - 50; 159 | [self.samplePoints removeObjectsInRange:range]; 160 | } 161 | } 162 | 163 | 164 | @end 165 | -------------------------------------------------------------------------------- /VZInspector/overview/memory/VZMemoryInspectorOverView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZMemoryInspectorOverView : UIView 8 | 9 | - (void)handleRead; 10 | - (void)handleWrite; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /VZInspector/overview/memory/VZMemoryInspectorOverView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #include 6 | #import "VZMemoryInspectorOverView.h" 7 | #import "VZInspectorPlotView.h" 8 | #import "VZMemoryInspector.h" 9 | #import "NSObject+VZInspector.h" 10 | 11 | 12 | const int kThreshHold = 60.0f; 13 | @implementation VZMemoryInspectorOverView 14 | { 15 | UILabel * _titleView; 16 | UILabel * _statusView; 17 | VZInspectorPlotView* _plotView1; 18 | } 19 | 20 | 21 | - (id)initWithFrame:(CGRect)frame 22 | { 23 | self = [super initWithFrame:frame]; 24 | 25 | if (self) { 26 | CGRect lineRect = CGRectMake(0, 0, frame.size.width, 1.0f); 27 | 28 | UIView *topLine = [[UIView alloc] initWithFrame:lineRect]; 29 | topLine.backgroundColor = [UIColor colorWithWhite:0.5f alpha:1.0f]; 30 | [self addSubview:topLine]; 31 | 32 | UIView *bottomLine = [[UIView alloc] initWithFrame:CGRectOffset(lineRect, 0, frame.size.height)]; 33 | bottomLine.backgroundColor = [UIColor colorWithWhite:0.5f alpha:1.0f]; 34 | [self addSubview:bottomLine]; 35 | 36 | CGRect titleFrame; 37 | titleFrame.size.width = 90.0f; 38 | titleFrame.size.height = 20.0f; 39 | titleFrame.origin.x = 8.0f; 40 | titleFrame.origin.y = 0.0f; 41 | 42 | _titleView = [[UILabel alloc] initWithFrame:titleFrame]; 43 | _titleView.textColor = [UIColor orangeColor]; 44 | _titleView.textAlignment = NSTextAlignmentLeft; 45 | _titleView.font = [UIFont boldSystemFontOfSize:12.0f]; 46 | _titleView.lineBreakMode = NSLineBreakByClipping; 47 | _titleView.backgroundColor = [UIColor clearColor]; 48 | _titleView.numberOfLines = 1; 49 | _titleView.text = @"Memory Usage"; 50 | [self addSubview:_titleView]; 51 | 52 | CGRect statusFrame; 53 | statusFrame.size.width = 200; 54 | statusFrame.size.height = 20.0f; 55 | statusFrame.origin.x = frame.size.width - 200-10; 56 | statusFrame.origin.y = 0.0f; 57 | 58 | _statusView = [[UILabel alloc] initWithFrame:statusFrame]; 59 | _statusView.textColor = [UIColor whiteColor]; 60 | _statusView.textAlignment = NSTextAlignmentRight; 61 | _statusView.font = [UIFont boldSystemFontOfSize:12.0f]; 62 | _statusView.lineBreakMode = NSLineBreakByClipping; 63 | _statusView.numberOfLines = 1; 64 | _statusView.backgroundColor = [UIColor clearColor]; 65 | [self addSubview:_statusView]; 66 | 67 | CGRect plotFrame; 68 | plotFrame.size.width = frame.size.width; 69 | plotFrame.size.height = frame.size.height - 20; 70 | plotFrame.origin.x = 0.0f; 71 | plotFrame.origin.y = 20.0f; 72 | 73 | _plotView1 = [[VZInspectorPlotView alloc] initWithFrame:plotFrame]; 74 | _plotView1.alpha = 0.6f; 75 | _plotView1.lowerBound = 0.0f; 76 | _plotView1.upperBound = 0.0f; 77 | _plotView1.lineColor = [UIColor orangeColor]; 78 | _plotView1.lineWidth = 2.0f; 79 | _plotView1.capacity = 50; 80 | _plotView1.fill = NO; 81 | [self addSubview:_plotView1]; 82 | } 83 | 84 | return self; 85 | } 86 | 87 | - (void)dealloc 88 | { 89 | //NSLog(@"[%@]-->dealloc",self.class); 90 | } 91 | 92 | - (void)handleRead 93 | { 94 | [[VZMemoryInspector sharedInstance] vz_heartBeat]; 95 | } 96 | - (void)handleWrite 97 | { 98 | [self writeHeartBeat]; 99 | } 100 | 101 | - (void)writeHeartBeat 102 | { 103 | //NSLog(@"writeHeartBeat"); 104 | 105 | float used = [VZMemoryInspector bytesOfUsedMemory]; 106 | float total = [VZMemoryInspector bytesOfTotalMemory]; 107 | 108 | float percent = (total > 0.0f) ? ((float)used / (float)total * 100.0f) : 0.0f; 109 | if ( percent >= kThreshHold ) 110 | { 111 | //预警 112 | [UIView animateWithDuration:0.6f 113 | delay:0.0f 114 | options: UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse 115 | animations: ^(void){self.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.6f];} 116 | completion:NULL]; 117 | } 118 | else 119 | { 120 | 121 | [UIView animateWithDuration:0.6f 122 | delay:0.0f 123 | options: UIViewAnimationOptionBeginFromCurrentState 124 | animations: ^(void){self.backgroundColor = [UIColor clearColor];} 125 | completion:NULL]; 126 | } 127 | 128 | NSMutableArray* tmp = [VZMemoryInspector sharedInstance].samplePoints; 129 | CGFloat _upperBound = 1; 130 | CGFloat _lowerBound = 0; 131 | 132 | for ( NSNumber * n in tmp ) 133 | { 134 | if ( n.intValue > _upperBound ) 135 | { 136 | _upperBound = n.intValue; 137 | if ( _upperBound < _lowerBound ) 138 | { 139 | _lowerBound = _upperBound; 140 | } 141 | } 142 | else if ( n.intValue < _lowerBound ) 143 | { 144 | _lowerBound = n.intValue; 145 | } 146 | } 147 | 148 | 149 | [_plotView1 setPlots:tmp]; 150 | [_plotView1 setLowerBound:_lowerBound]; 151 | [_plotView1 setUpperBound:_upperBound]; 152 | [_plotView1 setNeedsDisplay]; 153 | 154 | 155 | 156 | NSMutableString * text = [NSMutableString string]; 157 | [text appendFormat:@"used:%@ (%.0f%%) ", [self number2String:used], percent]; 158 | [text appendFormat:@"free:%@ ", [self number2String:total - used]]; 159 | _statusView.text = text; 160 | } 161 | 162 | #define KB (1024) 163 | #define MB (KB * 1024) 164 | #define GB (MB * 1024) 165 | 166 | - (NSString* )number2String:(int64_t)n 167 | { 168 | if ( n < KB ) 169 | { 170 | return [NSString stringWithFormat:@"%lldB", n]; 171 | } 172 | else if ( n < MB ) 173 | { 174 | return [NSString stringWithFormat:@"%.1fK", (float)n / (float)KB]; 175 | } 176 | else if ( n < GB ) 177 | { 178 | return [NSString stringWithFormat:@"%.1fM", (float)n / (float)MB]; 179 | } 180 | else 181 | { 182 | return [NSString stringWithFormat:@"%.1fG", (float)n / (float)GB]; 183 | } 184 | } 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /VZInspector/toolbox/VZInspectorToolItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | @interface VZInspectorToolItem : NSObject 9 | 10 | @property (nonatomic, strong) NSString *name; 11 | @property (nonatomic, strong) UIImage *icon; 12 | @property (nonatomic, strong) NSString *status; 13 | @property (nonatomic, strong) NSString *(^callback)(NSString *status); 14 | 15 | + (instancetype)itemWithName:(NSString *)name icon:(UIImage *)icon callback:(void(^)(void))callback; 16 | + (instancetype)switchItemWithName:(NSString *)name icon:(UIImage *)icon callback:(BOOL(^)(BOOL on))callback; 17 | + (instancetype)statusItemWithName:(NSString *)name icon:(UIImage *)icon callback:(NSString *(^)(NSString *status))callback; 18 | 19 | - (void)performAction; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /VZInspector/toolbox/VZInspectorToolItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorToolItem.h" 6 | 7 | @implementation VZInspectorToolItem 8 | 9 | + (instancetype)statusItemWithName:(NSString *)name icon:(UIImage *)icon callback:(NSString *(^)(NSString *status))callback { 10 | VZInspectorToolItem *item = [VZInspectorToolItem new]; 11 | item.name = name; 12 | item.icon = icon; 13 | item.callback = callback; 14 | return item; 15 | } 16 | 17 | + (instancetype)itemWithName:(NSString *)name icon:(UIImage *)icon callback:(void (^)(void))callback { 18 | return [self statusItemWithName:name icon:icon callback:^NSString *(NSString *status) { 19 | callback(); 20 | return status; 21 | }]; 22 | } 23 | 24 | + (instancetype)switchItemWithName:(NSString *)name icon:(UIImage *)icon callback:(BOOL (^)(BOOL on))callback { 25 | return [self statusItemWithName:name icon:icon callback:^(NSString *status) { 26 | return callback(!!status) ? @"ON" : nil; 27 | }]; 28 | } 29 | 30 | 31 | 32 | - (void)performAction { 33 | if (self.callback) { 34 | self.status = self.callback(self.status); 35 | } 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /VZInspector/toolbox/VZInspectorToolboxView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | #import "VZInspectorToolItem.h" 7 | 8 | @interface VZInspectorToolboxView : VZInspectorView 9 | 10 | - (void)addToolItem:(VZInspectorToolItem *)toolItem; 11 | - (void)setIcon:(UIImage *)icon; 12 | 13 | - (void)updateCollectionView; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /VZInspector/toolbox/VZInspectorToolboxView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | #import "VZInspectorToolboxView.h" 8 | #import "VZInspectorResource.h" 9 | #import "VZDefine.h" 10 | 11 | #define kVZInspectorToolItemCellReuseId @"kVZInspectorToolItemCellReuseId" 12 | 13 | 14 | @interface VZInspectorToolItemCell : UICollectionViewCell 15 | 16 | @property (nonatomic, strong) VZInspectorToolItem *item; 17 | 18 | @end 19 | 20 | @implementation VZInspectorToolItemCell 21 | { 22 | UIImageView *_iconView; 23 | UILabel *_nameLabel; 24 | UILabel *_statusLabel; 25 | UIView *_statusView; 26 | } 27 | 28 | - (void)setItem:(VZInspectorToolItem *)item { 29 | _item = item; 30 | _iconView.image = item.icon; 31 | _nameLabel.text = item.name; 32 | _statusView.hidden = !item.status; 33 | _statusLabel.text = item.status; 34 | } 35 | 36 | - (instancetype)initWithFrame:(CGRect)frame { 37 | if (self = [super initWithFrame:frame]) { 38 | self.contentView.clipsToBounds = YES; 39 | self.layer.borderWidth = kOnePix; 40 | self.layer.borderColor = VZ_INSPECTOR_MAIN_COLOR.CGColor; 41 | 42 | const CGFloat textHeight = 15; 43 | const CGFloat imageSize = 32; 44 | const CGFloat spacing = 3; 45 | const CGFloat totalHeight = textHeight + spacing + imageSize; 46 | 47 | _iconView = [[UIImageView alloc] initWithFrame:CGRectMake((frame.size.width - imageSize) / 2, (frame.size.height - totalHeight) / 2, imageSize, imageSize)]; 48 | _iconView.contentMode = UIViewContentModeScaleAspectFit; 49 | [self.contentView addSubview:_iconView]; 50 | 51 | _nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, _iconView.frame.origin.y + imageSize + spacing, frame.size.width, textHeight)]; 52 | _nameLabel.font = [UIFont systemFontOfSize:12.0]; 53 | _nameLabel.textColor = VZ_INSPECTOR_MAIN_COLOR; 54 | _nameLabel.textAlignment = NSTextAlignmentCenter; 55 | [self.contentView addSubview:_nameLabel]; 56 | 57 | CGFloat w = frame.size.width; 58 | _statusView = [[UIView alloc] init]; 59 | _statusView.layer.anchorPoint = CGPointMake(1, 1); 60 | _statusView.frame = CGRectMake(w - w * M_SQRT2 / 2, w / 2 - w * M_SQRT2 / 8, w * M_SQRT2 / 2, w * M_SQRT2 / 8); 61 | _statusView.transform = CGAffineTransformMakeRotation(M_PI_4); 62 | _statusView.backgroundColor = VZ_INSPECTOR_MAIN_COLOR; 63 | 64 | _statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(w * M_SQRT2 / 8, 0, w * M_SQRT2 / 4, w * M_SQRT2 / 8)]; 65 | _statusLabel.textColor = [UIColor whiteColor]; 66 | _statusLabel.textAlignment = NSTextAlignmentCenter; 67 | _statusLabel.font = [UIFont systemFontOfSize:10]; 68 | _statusLabel.adjustsFontSizeToFitWidth = YES; 69 | _statusLabel.minimumScaleFactor = 0.7; 70 | [_statusView addSubview:_statusLabel]; 71 | [self.contentView addSubview:_statusView]; 72 | } 73 | return self; 74 | } 75 | 76 | @end 77 | 78 | 79 | @interface VZInspectorToolboxView() 80 | 81 | @property (nonatomic, strong) NSMutableArray *tools; 82 | 83 | @end 84 | 85 | 86 | @implementation VZInspectorToolboxView 87 | { 88 | UICollectionView *_collectionView; 89 | UIImageView *_logoView; 90 | UIView *_emptyView; 91 | } 92 | 93 | - (id)initWithFrame:(CGRect)frame 94 | { 95 | self = [super initWithFrame:frame]; 96 | if (self) { 97 | UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; 98 | flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical; 99 | flowLayout.minimumInteritemSpacing = 0; 100 | flowLayout.minimumLineSpacing = 0; 101 | flowLayout.itemSize = CGSizeMake(frame.size.width / 5, frame.size.width / 5); 102 | _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 120, frame.size.width, frame.size.height - 120) collectionViewLayout:flowLayout]; 103 | _collectionView.dataSource = self; 104 | _collectionView.delegate = self; 105 | _collectionView.bounces = YES; 106 | _collectionView.showsHorizontalScrollIndicator = NO; 107 | _collectionView.showsVerticalScrollIndicator = NO; 108 | _collectionView.backgroundColor = [UIColor clearColor]; 109 | [_collectionView registerClass:[VZInspectorToolItemCell class] forCellWithReuseIdentifier:kVZInspectorToolItemCellReuseId]; 110 | [self addSubview:_collectionView]; 111 | 112 | _logoView = [[UIImageView alloc]initWithFrame:CGRectMake((frame.size.width - 60)/2, 30, 60, 60)]; 113 | _logoView.image = [VZInspectorResource logo]; 114 | _logoView.contentMode = UIViewContentModeScaleAspectFit; 115 | [self addSubview:_logoView]; 116 | 117 | UIView* line = [[UIView alloc] initWithFrame:CGRectMake(0, _collectionView.frame.origin.y, frame.size.width, 1)]; 118 | line.backgroundColor = VZ_INSPECTOR_MAIN_COLOR; 119 | [self addSubview:line]; 120 | 121 | UILabel *label = [[UILabel alloc] initWithFrame:_collectionView.frame]; 122 | label.text = @"No Plugins"; 123 | label.textColor = VZ_INSPECTOR_MAIN_COLOR; 124 | label.font = [UIFont systemFontOfSize:24]; 125 | label.textAlignment = NSTextAlignmentCenter; 126 | [self addSubview:label]; 127 | _emptyView = label; 128 | } 129 | 130 | return self; 131 | } 132 | 133 | - (void)dealloc { 134 | _collectionView.delegate = nil; 135 | _collectionView.dataSource = nil; 136 | } 137 | 138 | - (void)setIcon:(UIImage *)icon { 139 | _logoView.image = icon; 140 | } 141 | 142 | - (NSMutableArray *)tools { 143 | if (!_tools) { 144 | _tools = [NSMutableArray array]; 145 | } 146 | return _tools; 147 | } 148 | 149 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 150 | { 151 | return self.tools.count; 152 | } 153 | 154 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 155 | { 156 | VZInspectorToolItemCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kVZInspectorToolItemCellReuseId forIndexPath:indexPath]; 157 | cell.item = self.tools[indexPath.item]; 158 | return cell; 159 | } 160 | 161 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { 162 | VZInspectorToolItem *item = self.tools[indexPath.item]; 163 | [item performAction]; 164 | [_collectionView reloadItemsAtIndexPaths:@[indexPath]]; 165 | } 166 | 167 | - (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath { 168 | UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; 169 | cell.backgroundColor = [VZ_INSPECTOR_MAIN_COLOR colorWithAlphaComponent:0.3]; 170 | } 171 | 172 | - (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(nonnull NSIndexPath *)indexPath { 173 | UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; 174 | cell.backgroundColor = [UIColor clearColor]; 175 | } 176 | 177 | - (void)addToolItem:(VZInspectorToolItem *)toolItem { 178 | [self.tools addObject:toolItem]; 179 | _emptyView.hidden = YES; 180 | } 181 | 182 | - (void)updateCollectionView{ 183 | if(_collectionView){ 184 | [_collectionView reloadData]; 185 | } 186 | } 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /VZInspector/toolbox/border/VZBorderInspector.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZBorderInspector : NSObject 8 | 9 | @property(nonatomic,assign,readonly) BOOL isON; 10 | 11 | + (instancetype)sharedInstance; 12 | + (void)setViewClassPrefixName:(NSString* )name; 13 | 14 | - (void)showBorder; 15 | - (void)showViewClassName; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /VZInspector/toolbox/border/VZBorderInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZBorderInspector.h" 6 | #import "VZInspectorTimer.h" 7 | #import 8 | #import 9 | 10 | @interface UIView(VZBorderLayerTag) 11 | 12 | @property(nonatomic,strong) NSNumber* layerTag; 13 | 14 | @end 15 | 16 | @implementation UIView(VZBorderLayerTag) 17 | 18 | - (void)setLayerTag:(NSNumber *)layerTag 19 | { 20 | objc_setAssociatedObject(self, "VZBorderLayerTag", layerTag, OBJC_ASSOCIATION_RETAIN); 21 | } 22 | 23 | - (NSNumber* )layerTag 24 | { 25 | return objc_getAssociatedObject(self, "VZBorderLayerTag"); 26 | } 27 | 28 | - (UIView* )viewWithLayerTag:(NSNumber* )layerTag 29 | { 30 | UIView* v = nil; 31 | 32 | for (UIView* subview in self.subviews) 33 | { 34 | if ([v.layerTag integerValue] == [layerTag integerValue]) { 35 | v = subview; 36 | break; 37 | } 38 | } 39 | 40 | return v; 41 | } 42 | 43 | @end 44 | 45 | 46 | @interface NSTimer(VZBorderInspector) 47 | +(NSTimer* )scheduledTimerWithTimeInterval:(NSTimeInterval)ti block:(void(^)(void))block userInfo:(id)userInfo repeats:(BOOL)repeat; 48 | @end 49 | 50 | @implementation NSTimer(VZBorderInspector) 51 | 52 | + (NSTimer* )scheduledTimerWithTimeInterval:(NSTimeInterval)ti block:(void (^)(void))block userInfo:(id)userInfo repeats:(BOOL)repeat 53 | { 54 | return [NSTimer scheduledTimerWithTimeInterval:ti target:self selector:@selector(onTimerFired:) userInfo:[block copy] repeats:repeat]; 55 | } 56 | 57 | + (void)onTimerFired:(NSTimer* )timer 58 | { 59 | void(^block)(void) = timer.userInfo; 60 | 61 | if (block) { 62 | block(); 63 | } 64 | } 65 | 66 | @end 67 | 68 | #define kVZBorderLayerTag 729 69 | 70 | @interface VZBorderItem:NSObject 71 | 72 | @property(nonatomic,weak) UIView* view; 73 | @property(nonatomic,assign) CGFloat borderWidth; 74 | @property(nonatomic,strong) UIColor* borderColor; 75 | 76 | 77 | @end 78 | 79 | @implementation VZBorderItem 80 | @end 81 | 82 | @interface VZBorderInspector () 83 | { 84 | BOOL _on; 85 | NSMutableSet* _set; 86 | } 87 | 88 | @property(nonatomic,strong) NSTimer* timer; 89 | @property(nonatomic,strong) NSString* prefixName; 90 | @property(nonatomic,assign) float borderWidth; 91 | 92 | 93 | @end 94 | 95 | @implementation VZBorderInspector 96 | 97 | + (instancetype)sharedInstance { 98 | static VZBorderInspector *instance; 99 | static dispatch_once_t onceToken; 100 | dispatch_once(&onceToken, ^{ 101 | if (!instance) { 102 | instance = [VZBorderInspector new]; 103 | } 104 | }); 105 | 106 | return instance; 107 | } 108 | 109 | + (void)setViewClassPrefixName:(NSString* )name 110 | { 111 | [[self sharedInstance] setPrefixName:name]; 112 | } 113 | 114 | - (BOOL)isON 115 | { 116 | return _on; 117 | } 118 | 119 | - (id)init 120 | { 121 | self = [super init]; 122 | 123 | if (self) { 124 | 125 | _borderWidth = 0.5; 126 | _set = [NSMutableSet new]; 127 | 128 | } 129 | return self; 130 | } 131 | 132 | - (void)dealloc 133 | { 134 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 135 | } 136 | 137 | - (void)showBorder 138 | { 139 | _on = !_on; 140 | 141 | if (_on) { 142 | 143 | __weak typeof(self) weakSelf = self; 144 | self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 block:^{ 145 | 146 | [weakSelf timerTriggered]; 147 | 148 | } userInfo:nil repeats:YES]; 149 | } 150 | else 151 | { 152 | [self.timer invalidate]; 153 | self.timer = nil; 154 | [self timerStopped]; 155 | } 156 | } 157 | 158 | - (void)showViewClassName 159 | { 160 | //todo... 161 | } 162 | 163 | - (void)timerTriggered 164 | { 165 | if (_on) 166 | { 167 | [self recoverViewBorder]; 168 | [_set removeAllObjects]; 169 | [self updateBorderOfViewHierarchy]; 170 | } 171 | } 172 | 173 | - (void)timerStopped 174 | { 175 | if (!_on) 176 | { 177 | [self recoverViewBorder]; 178 | [_set removeAllObjects]; 179 | } 180 | } 181 | 182 | 183 | 184 | - (void)updateBorderOfViewHierarchy { 185 | 186 | UIViewController *currentVC = nil; 187 | UIWindow * window = [[UIApplication sharedApplication] keyWindow]; 188 | UIView *frontView = [[window subviews] objectAtIndex:0]; 189 | id nextResponder = [frontView nextResponder]; 190 | 191 | if ([nextResponder isKindOfClass:[UIViewController class]]) 192 | currentVC = nextResponder; 193 | else 194 | currentVC = window.rootViewController; 195 | 196 | [self drawBorderOfViewHierarchy:currentVC.view]; 197 | } 198 | 199 | - (void)drawBorderOfViewHierarchy:(UIView *)view { 200 | 201 | //all border 202 | VZBorderItem* item = [VZBorderItem new]; 203 | item.borderColor = [UIColor colorWithCGColor:view.layer.borderColor]; 204 | item.borderWidth = view.layer.borderWidth; 205 | item.view = view; 206 | [_set addObject:item]; 207 | 208 | view.layer.borderWidth = self.borderWidth; 209 | view.layer.borderColor = [UIColor orangeColor].CGColor; 210 | 211 | NSString* className = NSStringFromClass([view class]); 212 | 213 | if (self.prefixName.length > 0 ) 214 | { 215 | 216 | if ([className hasPrefix:self.prefixName]) { 217 | 218 | if ([view viewWithTag:kVZBorderLayerTag]) { 219 | 220 | UILabel* label = (UILabel* )[view viewWithTag:kVZBorderLayerTag]; 221 | label.text = className; 222 | } 223 | else 224 | { 225 | UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, view.bounds.size.width, 12)]; 226 | label.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.5]; 227 | label.textAlignment = NSTextAlignmentLeft; 228 | label.text = className; 229 | label.textColor = [UIColor cyanColor]; 230 | label.font = [UIFont systemFontOfSize:9.0]; 231 | label.tag = kVZBorderLayerTag; 232 | //label.layerTag = @(kVZBorderLayerTag); 233 | [view addSubview:label]; 234 | } 235 | 236 | } 237 | } 238 | for (UIView* subview in view.subviews) 239 | { 240 | if (subview.tag == kVZBorderLayerTag) { 241 | continue; 242 | } 243 | [self drawBorderOfViewHierarchy:subview]; 244 | } 245 | } 246 | 247 | - (void)recoverViewBorder 248 | { 249 | [_set enumerateObjectsUsingBlock:^(VZBorderItem* obj, BOOL *stop) { 250 | 251 | if (obj.view) 252 | { 253 | [[obj.view viewWithTag:kVZBorderLayerTag] removeFromSuperview]; 254 | obj.view.layer.borderWidth = obj.borderWidth; 255 | obj.view.layer.borderColor = obj.borderColor.CGColor; 256 | } 257 | }]; 258 | } 259 | 260 | 261 | 262 | 263 | 264 | @end 265 | -------------------------------------------------------------------------------- /VZInspector/toolbox/colorPicker/VZColorDisplayView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @class VZColorDisplayView; 8 | 9 | @protocol VZColorDisplayViewDelegate 10 | 11 | - (void)displayView:(VZColorDisplayView *)displayView colorDidUpdate:(UIColor *)color; 12 | 13 | @end 14 | 15 | //宽高要设置成奇数 16 | @interface VZColorDisplayView : UIView 17 | 18 | + (instancetype)displayViewWithRadius:(CGFloat)r scale:(NSUInteger)scale; 19 | 20 | 21 | @property (nonatomic, assign) NSUInteger scale; //放大倍数,>=1 22 | @property (nonatomic, weak) id delegate; 23 | 24 | - (void)update; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /VZInspector/toolbox/colorPicker/VZColorPanelView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @class VZColorPanelView; 8 | 9 | @protocol VZColorPanelViewDelegate 10 | 11 | - (void)panelView:(VZColorPanelView *)panelView ratioDidChange:(NSInteger )ratio; 12 | 13 | @end 14 | 15 | @interface VZColorPanelView : UIView 16 | 17 | @property (nonatomic, weak) id delegate; 18 | 19 | - (void)updateColor:(UIColor *)color; 20 | 21 | - (id)initWithFrame:(CGRect)frame defaultRatio:(NSInteger)defaultRatio; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /VZInspector/toolbox/colorPicker/VZColorPickerDefine.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #ifndef VZColorPickerDefine_h 6 | #define VZColorPickerDefine_h 7 | 8 | static const NSUInteger kVZCPMinZoomValue = 5; 9 | static const NSUInteger kVZCPMaxZoomValue = 30; 10 | 11 | 12 | #endif /* VZColorPickerDefine_h */ 13 | -------------------------------------------------------------------------------- /VZInspector/toolbox/colorPicker/VZInspectorColorPickerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @interface VZInspectorColorPickerView : VZInspectorView 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /VZInspector/toolbox/colorPicker/VZInspectorColorPickerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorColorPickerView.h" 6 | #import "VZColorDisplayView.h" 7 | #import "VZColorPanelView.h" 8 | 9 | @interface VZInspectorColorPickerView() 10 | 11 | @property(nonatomic,strong)UIButton* backBtn; 12 | @property(nonatomic,strong)VZColorDisplayView *colorDisplayView; 13 | @property(nonatomic,strong)VZColorPanelView *colorPanelView; 14 | 15 | @property(nonatomic,assign) CGPoint fromPoint; 16 | @property(nonatomic,assign) CGPoint touchFromPoint; 17 | @property(nonatomic,assign) BOOL isMoving; 18 | @property(nonatomic,assign) BOOL isFromCircle;//是否从圆圈开始拖动 19 | @end 20 | 21 | 22 | @implementation VZInspectorColorPickerView 23 | 24 | /* 25 | // Only override drawRect: if you perform custom drawing. 26 | // An empty implementation adversely affects performance during animation. 27 | - (void)drawRect:(CGRect)rect { 28 | // Drawing code 29 | } 30 | */ 31 | 32 | - (id)initWithFrame:(CGRect)frame parentViewController:(UIViewController *)controller { 33 | self = [super initWithFrame:frame parentViewController:controller]; 34 | if (self) { 35 | self.backgroundColor = [UIColor clearColor]; 36 | 37 | self.backBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 0, 44, 44)]; 38 | self.backBtn.backgroundColor = [UIColor clearColor]; 39 | [self.backBtn setTitle:@"<-" forState:UIControlStateNormal]; 40 | [self.backBtn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; 41 | self.backBtn.titleLabel.font = [UIFont systemFontOfSize:18.0f]; 42 | #pragma clang diagnostic push 43 | #pragma clang diagnostic ignored "-Wundeclared-selector" 44 | [self.backBtn addTarget:self.parentViewController action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside]; 45 | #pragma clang diagnostic pop 46 | [self addSubview:self.backBtn]; 47 | 48 | NSUInteger defaultScale = 5; 49 | 50 | self.colorDisplayView = [VZColorDisplayView displayViewWithRadius:101 scale:defaultScale]; 51 | self.colorDisplayView.center = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * 0.5); 52 | self.colorDisplayView.delegate = self; 53 | [self addSubview:self.colorDisplayView]; 54 | 55 | [self.colorDisplayView update]; 56 | 57 | 58 | self.colorPanelView = [[VZColorPanelView alloc] initWithFrame:CGRectMake(0, self.frame.size.height - 150, self.frame.size.width, 150) defaultRatio:defaultScale]; 59 | self.colorPanelView.delegate = self; 60 | [self.colorPanelView updateColor:[UIColor colorWithWhite:0.3 alpha:0.2]]; 61 | [self addSubview:self.colorPanelView]; 62 | 63 | self.multipleTouchEnabled = NO; 64 | } 65 | return self; 66 | } 67 | 68 | - (void)displayView:(VZColorDisplayView *)displayView colorDidUpdate:(UIColor *)color { 69 | [self.colorPanelView updateColor:color]; 70 | } 71 | 72 | - (void)panelView:(VZColorPanelView *)panelView ratioDidChange:(NSInteger )ratio { 73 | if (ratio <= 1) { 74 | ratio = 1; 75 | } 76 | [self.colorDisplayView setScale:ratio]; 77 | } 78 | 79 | - (BOOL)isTouchInDisplayView:(UITouch *)touch { 80 | CGPoint touchPoint = [touch locationInView:self]; 81 | return CGRectContainsPoint(self.colorDisplayView.frame, touchPoint); 82 | } 83 | 84 | - (void)touchesBegan:(NSSet *)touches withEvent:(nullable UIEvent *)event { 85 | 86 | do { 87 | if ([touches count] != 1) { 88 | break; 89 | } 90 | 91 | UITouch *touch = [touches anyObject]; 92 | 93 | self.isFromCircle = [self isTouchInDisplayView:touch]; 94 | 95 | self.isMoving = YES; 96 | self.fromPoint = self.colorDisplayView.frame.origin; 97 | self.touchFromPoint = [touch locationInView:self]; 98 | return; 99 | } while (0); 100 | 101 | 102 | [super touchesBegan:touches withEvent:event]; 103 | 104 | 105 | } 106 | 107 | - (void)touchesMoved:(NSSet *)touches withEvent:(nullable UIEvent *)event { 108 | if (!self.isMoving) { 109 | return [super touchesMoved:touches withEvent:event]; 110 | } 111 | 112 | UITouch *touch = [touches anyObject]; 113 | 114 | CGPoint touchPoint = [touch locationInView:self]; 115 | 116 | CGRect frame = self.colorDisplayView.frame; 117 | 118 | CGFloat rate = self.isFromCircle ? 1 : 0.03; 119 | 120 | //整像素点 121 | frame.origin.x = rate * (touchPoint.x - self.touchFromPoint.x) + self.fromPoint.x; 122 | frame.origin.y = rate * (touchPoint.y - self.touchFromPoint.y) + self.fromPoint.y; 123 | 124 | [self updateColorDisplayViewFrame:frame]; 125 | } 126 | 127 | - (void)updateColorDisplayViewFrame:(CGRect)frame { 128 | 129 | CGFloat scale = [[UIScreen mainScreen] scale]; 130 | 131 | //四舍五入 132 | frame.origin.x = floor((frame.origin.x) * scale + 0.5) / scale; 133 | frame.origin.y = floor((frame.origin.y) * scale + 0.5) / scale; 134 | 135 | if (frame.origin.x < self.bounds.origin.x - frame.size.width * 0.5) { 136 | frame.origin.x = self.bounds.origin.x - frame.size.width * 0.5; 137 | } 138 | 139 | if (frame.origin.x > self.bounds.origin.x + self.bounds.size.width - frame.size.width * 0.5) { 140 | frame.origin.x = self.bounds.origin.x + self.bounds.size.width - frame.size.width * 0.5; 141 | } 142 | 143 | if (frame.origin.y < self.bounds.origin.y - frame.size.height * 0.5) { 144 | frame.origin.y = self.bounds.origin.y - frame.size.height * 0.5; 145 | } 146 | 147 | if (frame.origin.y > self.bounds.origin.y + self.bounds.size.height - frame.size.height * 0.5) { 148 | frame.origin.y = self.bounds.origin.y + self.bounds.size.height - frame.size.height * 0.5; 149 | } 150 | 151 | if (frame.origin.x != self.colorDisplayView.frame.origin.x 152 | || frame.origin.y != self.colorDisplayView.frame.origin.y) { 153 | //防止频繁刷新 154 | self.colorDisplayView.frame = frame; 155 | 156 | [self.colorDisplayView update]; 157 | } 158 | 159 | 160 | CGRect panelDownFrame = self.colorPanelView.frame; //在下边时候的frame 161 | panelDownFrame.origin.y = self.frame.size.height - self.colorPanelView.frame.size.height; 162 | 163 | if (CGRectIntersectsRect(self.colorDisplayView.frame, panelDownFrame)) { 164 | CGRect frame = self.colorPanelView.frame; 165 | frame.origin.y = 0; 166 | self.colorPanelView.frame = frame; 167 | 168 | frame = self.backBtn.frame; 169 | frame.origin.y = self.colorPanelView.frame.origin.y + self.colorPanelView.frame.size.height + 10; 170 | self.backBtn.frame = frame; 171 | } else { 172 | self.colorPanelView.frame = panelDownFrame; 173 | 174 | CGRect frame = self.backBtn.frame; 175 | frame.origin.y = 0; 176 | self.backBtn.frame = frame; 177 | } 178 | } 179 | 180 | 181 | - (void)touchesEnded:(NSSet *)touches withEvent:(nullable UIEvent *)event { 182 | if (!_isMoving) { 183 | [super touchesEnded:touches withEvent:event]; 184 | } 185 | self.isMoving = NO; 186 | } 187 | - (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *) event { 188 | if (!self.isMoving) { 189 | [super touchesCancelled:touches withEvent:event]; 190 | } 191 | self.isMoving = NO; 192 | } 193 | 194 | @end 195 | -------------------------------------------------------------------------------- /VZInspector/toolbox/crash/VZCrashInspector.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZCrashInspector : NSObject 8 | 9 | + (instancetype)sharedInstance; 10 | - (void)install; 11 | - (NSDictionary* )crashForKey:(NSString* )key; 12 | - (NSArray* )crashPlist; 13 | - (NSArray* )crashLogs; 14 | 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /VZInspector/toolbox/crash/VZCrashInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZCrashInspector.h" 6 | #include 7 | #include 8 | 9 | @implementation VZCrashInspector 10 | 11 | { 12 | BOOL _isInstalled; 13 | NSString* _crashLogPath; 14 | NSMutableArray* _plist; 15 | } 16 | 17 | + (instancetype)sharedInstance 18 | { 19 | static VZCrashInspector* instance; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | instance = [VZCrashInspector new]; 23 | }); 24 | return instance; 25 | } 26 | 27 | const int maxCrashLogNum = 20; 28 | 29 | //handle exception 30 | 31 | void vz_HandleException(NSException *exception) 32 | { 33 | [[VZCrashInspector sharedInstance]saveException:exception]; 34 | [exception raise]; 35 | } 36 | 37 | void vz_SignalHandler(int sig) 38 | { 39 | [[VZCrashInspector sharedInstance]saveSignal:sig]; 40 | 41 | signal(sig, SIG_DFL); 42 | raise(sig); 43 | } 44 | 45 | + (NSArray *)backtrace 46 | { 47 | void* callstack[128]; 48 | int frames = backtrace(callstack, 128); 49 | char **strs = backtrace_symbols(callstack, frames); 50 | 51 | NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames]; 52 | 53 | for (int i = 0;i < 32;i++) 54 | { 55 | [backtrace addObject:[NSString stringWithUTF8String:strs[i]]]; 56 | } 57 | free(strs); 58 | 59 | return backtrace; 60 | } 61 | 62 | - (id)init 63 | { 64 | self = [super init]; 65 | if ( self ) 66 | { 67 | NSArray * paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); 68 | NSString* sandBoxPath = [paths objectAtIndex:0]; 69 | 70 | 71 | _crashLogPath = [sandBoxPath stringByAppendingPathComponent:@"VZCrashLog"]; 72 | 73 | if ( NO == [[NSFileManager defaultManager] fileExistsAtPath:_crashLogPath] ) 74 | { 75 | [[NSFileManager defaultManager] createDirectoryAtPath:_crashLogPath 76 | withIntermediateDirectories:YES 77 | attributes:nil 78 | error:NULL]; 79 | } 80 | 81 | //creat plist 82 | if (YES == [[NSFileManager defaultManager] fileExistsAtPath:[_crashLogPath stringByAppendingPathComponent:@"crashLog.plist"]]) 83 | { 84 | _plist = [[NSMutableArray arrayWithContentsOfFile:[_crashLogPath stringByAppendingPathComponent:@"crashLog.plist"]] mutableCopy]; 85 | } 86 | else 87 | _plist = [NSMutableArray new]; 88 | } 89 | return self; 90 | } 91 | 92 | - (NSDictionary* )crashForKey:(NSString *)key 93 | { 94 | NSString* filePath = [[_crashLogPath stringByAppendingPathComponent:key] stringByAppendingString:@".plist"]; 95 | NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:filePath]; 96 | 97 | return dict; 98 | } 99 | 100 | - (NSArray* )crashPlist 101 | { 102 | return [_plist copy]; 103 | } 104 | 105 | - (NSArray* )crashLogs 106 | { 107 | NSMutableArray* ret = [NSMutableArray new]; 108 | for (NSString* key in _plist) { 109 | 110 | NSString* filePath = [_crashLogPath stringByAppendingPathComponent:key]; 111 | NSString* path = [filePath stringByAppendingString:@".plist"]; 112 | NSDictionary* log = [NSDictionary dictionaryWithContentsOfFile:path]; 113 | [ret addObject:log]; 114 | } 115 | return [ret copy]; 116 | } 117 | 118 | 119 | - (NSDictionary* )crashReport 120 | { 121 | for (NSString* key in _plist) { 122 | 123 | NSString* filePath = [_crashLogPath stringByAppendingPathComponent:key]; 124 | 125 | NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:filePath]; 126 | 127 | return dict; 128 | } 129 | return nil; 130 | 131 | } 132 | 133 | - (void)install 134 | { 135 | if (_isInstalled) { 136 | return; 137 | } 138 | //注册回调函数 139 | NSSetUncaughtExceptionHandler(&vz_HandleException); 140 | signal(SIGABRT, vz_SignalHandler); 141 | signal(SIGILL, vz_SignalHandler); 142 | signal(SIGSEGV, vz_SignalHandler); 143 | signal(SIGFPE, vz_SignalHandler); 144 | signal(SIGBUS, vz_SignalHandler); 145 | signal(SIGPIPE, vz_SignalHandler); 146 | } 147 | 148 | - (void)dealloc 149 | { 150 | signal( SIGABRT, SIG_DFL ); 151 | signal( SIGBUS, SIG_DFL ); 152 | signal( SIGFPE, SIG_DFL ); 153 | signal( SIGILL, SIG_DFL ); 154 | signal( SIGPIPE, SIG_DFL ); 155 | signal( SIGSEGV, SIG_DFL ); 156 | } 157 | 158 | - (void)saveException:(NSException*)exception 159 | { 160 | NSMutableDictionary * detail = [NSMutableDictionary dictionary]; 161 | if ( exception.name ) 162 | { 163 | [detail setObject:exception.name forKey:@"name"]; 164 | } 165 | if ( exception.reason ) 166 | { 167 | [detail setObject:exception.reason forKey:@"reason"]; 168 | } 169 | if ( exception.userInfo ) 170 | { 171 | [detail setObject:exception.userInfo forKey:@"userInfo"]; 172 | } 173 | if ( exception.callStackSymbols ) 174 | { 175 | [detail setObject:exception.callStackSymbols forKey:@"callStack"]; 176 | } 177 | 178 | NSMutableDictionary * dict = [NSMutableDictionary dictionary]; 179 | [dict setObject:@"exception" forKey:@"type"]; 180 | [dict setObject:detail forKey:@"info"]; 181 | 182 | [self saveToFile:dict]; 183 | 184 | } 185 | 186 | - (void)saveSignal:(int) signal 187 | { 188 | // NSMutableDictionary * detail = [NSMutableDictionary dictionary]; 189 | // 190 | // [detail setObject:@(signal) forKey:@"signal type"]; 191 | 192 | // [self saveToFile:detail]; 193 | } 194 | 195 | - (void)saveToFile:(NSMutableDictionary*)dict 196 | { 197 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 198 | [formatter setDateFormat:@"yyyyMMdd_HHmmss"]; 199 | NSString* dateString = [formatter stringFromDate:[NSDate date]]; 200 | 201 | //add date 202 | [dict setObject:dateString forKey:@"date"]; 203 | 204 | //save path 205 | NSString* savePath = [[_crashLogPath stringByAppendingPathComponent:dateString] stringByAppendingString:@".plist"]; 206 | 207 | //save to disk 208 | BOOL succeed = [ dict writeToFile:savePath atomically:YES]; 209 | if ( NO == succeed ) 210 | { 211 | NSLog(@"VZInspector:Save crash report failed!"); 212 | } 213 | else 214 | NSLog(@"VZInspector:save crash report succeed!"); 215 | 216 | [_plist insertObject:dateString atIndex:0]; 217 | // [_plist writeToFile:[_crashLogPath stringByAppendingPathComponent:@"crashLog.plist"] atomically:YES]; 218 | 219 | if (_plist.count > maxCrashLogNum) 220 | { 221 | [[NSFileManager defaultManager] removeItemAtPath:[_crashLogPath stringByAppendingPathComponent:_plist[0]] error:nil]; 222 | [_plist removeObjectAtIndex:0]; 223 | 224 | } 225 | [_plist writeToFile:[_crashLogPath stringByAppendingPathComponent:@"crashLog.plist"] atomically:YES]; 226 | } 227 | 228 | @end 229 | -------------------------------------------------------------------------------- /VZInspector/toolbox/crash/VZInspectorCrashRootView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import "VZInspectorView.h" 7 | 8 | @interface VZInspectorCrashRootView : VZInspectorView 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /VZInspector/toolbox/crash/VZInspectorCrashRootView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorCrashRootView.h" 6 | #import "VZInspectorCrashView.h" 7 | #import "VZCrashInspector.h" 8 | 9 | 10 | @interface VZInspectorCrashRootHeaderView : UIView 11 | 12 | @property(nonatomic,strong) UILabel* textLabel; 13 | @property(nonatomic,strong) UIButton* backBtn; 14 | @property(nonatomic,weak) id delegate; 15 | 16 | @end 17 | 18 | @implementation VZInspectorCrashRootHeaderView 19 | 20 | - (id)initWithFrame:(CGRect)frame 21 | { 22 | self = [super initWithFrame:frame]; 23 | 24 | if (self) { 25 | 26 | self.textLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 13, frame.size.width, 18)]; 27 | self.textLabel.textAlignment = NSTextAlignmentCenter; 28 | self.textLabel.textColor = [UIColor whiteColor]; 29 | self.textLabel.backgroundColor = [UIColor clearColor]; 30 | self.textLabel.font = [UIFont systemFontOfSize:18.0f]; 31 | [self addSubview:self.textLabel]; 32 | 33 | self.backBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 0, 44, 44)]; 34 | self.backBtn.backgroundColor = [UIColor clearColor]; 35 | [self.backBtn setTitle:@"<-" forState:UIControlStateNormal]; 36 | [self.backBtn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; 37 | self.backBtn.titleLabel.font = [UIFont systemFontOfSize:18.0f]; 38 | #pragma clang diagnostic push 39 | #pragma clang diagnostic ignored "-Wundeclared-selector" 40 | [self.backBtn addTarget:self.delegate action:@selector(pop) forControlEvents:UIControlEventTouchUpInside]; 41 | #pragma clang diagnostic pop 42 | [self addSubview:self.backBtn]; 43 | } 44 | return self; 45 | } 46 | 47 | @end 48 | 49 | @interface VZInspectorCrashRootView() 50 | 51 | @property(nonatomic,strong)VZInspectorCrashRootHeaderView* headerView; 52 | @property(nonatomic,strong)NSString* filename; 53 | @property(nonatomic,strong)UIView* contentView; 54 | @property(nonatomic,strong)UITableView* listView; 55 | @property(nonatomic,strong)VZInspectorCrashView* subView; 56 | @property(nonatomic,strong)NSArray* pathNames; 57 | 58 | 59 | @end 60 | 61 | @implementation VZInspectorCrashRootView 62 | 63 | - (id)initWithFrame:(CGRect)frame parentViewController:(UIViewController *)controller 64 | { 65 | self = [super initWithFrame:frame parentViewController:controller]; 66 | 67 | if (self) { 68 | 69 | 70 | //contentview 71 | self.contentView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; 72 | self.contentView.backgroundColor = [UIColor clearColor]; 73 | [self addSubview:self.contentView]; 74 | 75 | 76 | //header view 77 | self.headerView = [[VZInspectorCrashRootHeaderView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, 44)]; 78 | self.headerView.delegate = self; 79 | self.headerView.textLabel.text = @"All Crashes"; 80 | [self.contentView addSubview:self.headerView]; 81 | 82 | //list view 83 | self.listView = [[UITableView alloc]initWithFrame:CGRectMake(0, 44, self.frame.size.width, self.frame.size.height-44)]; 84 | self.listView.backgroundColor = [UIColor clearColor]; 85 | self.listView.delegate = self; 86 | self.listView.dataSource = self; 87 | [self.contentView addSubview:self.listView]; 88 | 89 | //load data 90 | self.pathNames = [VZCrashInspector sharedInstance].crashPlist; 91 | 92 | 93 | //add subview 94 | self.subView = [[VZInspectorCrashView alloc]initWithFrame:CGRectMake(self.frame.size.width, 0, self.frame.size.width, self.frame.size.height)]; 95 | self.subView.delegate = self; 96 | [self addSubview:self.subView]; 97 | 98 | } 99 | return self; 100 | } 101 | 102 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 103 | { 104 | return 1; 105 | } 106 | 107 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 108 | { 109 | return self.pathNames.count; 110 | } 111 | 112 | - (UITableViewCell* )tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 113 | { 114 | static NSString* sandCellId = @"crashIdentifier"; 115 | 116 | UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:sandCellId]; 117 | if (!cell) { 118 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:sandCellId]; 119 | cell.backgroundColor = [UIColor clearColor]; 120 | cell.textLabel.textColor = [UIColor orangeColor]; 121 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 122 | [cell addGestureRecognizer:[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(onSelfClicked:)]]; 123 | } 124 | 125 | cell.textLabel.text = self.pathNames[indexPath.row]; 126 | cell.tag = indexPath.row; 127 | 128 | 129 | return cell; 130 | } 131 | 132 | 133 | - (void)onSelfClicked:(UITapGestureRecognizer* )tap 134 | { 135 | UIView* view = tap.view; 136 | NSInteger index = view.tag; 137 | 138 | if (index < self.pathNames.count) { 139 | 140 | NSString* path = self.pathNames[index]; 141 | self.subView.path = path; 142 | 143 | [UIView animateWithDuration:0.4 animations:^{ 144 | 145 | self.contentView.frame = CGRectMake(-CGRectGetWidth(self.bounds), 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)); 146 | self.subView.frame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)); 147 | 148 | } completion:^(BOOL finished) { 149 | 150 | }]; 151 | 152 | } 153 | } 154 | 155 | - (void)onBack { 156 | [UIView animateWithDuration:0.4 animations:^{ 157 | 158 | self.contentView.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)); 159 | self.subView.frame = CGRectMake(CGRectGetWidth(self.frame), 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)); 160 | 161 | 162 | } completion:^(BOOL finished) { 163 | 164 | 165 | }]; 166 | } 167 | 168 | @end 169 | 170 | 171 | -------------------------------------------------------------------------------- /VZInspector/toolbox/crash/VZInspectorCrashView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @protocol VZInspectorCrashViewCallBackProtocol 8 | 9 | @optional 10 | - (void)onBack; 11 | 12 | 13 | @end 14 | 15 | 16 | @interface VZInspectorCrashView : VZInspectorView 17 | 18 | @property(nonatomic,weak) id delegate; 19 | @property(nonatomic,strong) NSString* path; 20 | 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /VZInspector/toolbox/crash/VZInspectorCrashView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #include 6 | #import "VZInspectorCrashView.h" 7 | #import "VZCrashInspector.h" 8 | 9 | @interface VZInspectorCrashView() 10 | 11 | @property(nonatomic,strong) UITextView* crashLogs; 12 | @property(nonatomic,strong) UILabel* textLabel; 13 | @property(nonatomic,strong) UIButton* backBtn; 14 | 15 | @end 16 | 17 | @implementation VZInspectorCrashView 18 | 19 | - (id)initWithFrame:(CGRect)frame 20 | { 21 | self = [super initWithFrame:frame]; 22 | if (self) { 23 | 24 | self.textLabel = [[UILabel alloc]initWithFrame:CGRectMake(40, 0, frame.size.width-80, 44)]; 25 | self.textLabel.text = @"CrashLogs"; 26 | self.textLabel.textAlignment = NSTextAlignmentCenter; 27 | self.textLabel.textColor = [UIColor whiteColor]; 28 | self.textLabel.backgroundColor = [UIColor clearColor]; 29 | self.textLabel.font = [UIFont systemFontOfSize:18.0f]; 30 | [self addSubview:self.textLabel]; 31 | 32 | self.backBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 0, 44, 44)]; 33 | self.backBtn.backgroundColor = [UIColor clearColor]; 34 | [self.backBtn setTitle:@"<-" forState:UIControlStateNormal]; 35 | [self.backBtn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; 36 | self.backBtn.titleLabel.font = [UIFont systemFontOfSize:18.0f]; 37 | 38 | [self.backBtn addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside]; 39 | #pragma clang diagnostic pop 40 | [self addSubview:self.backBtn]; 41 | 42 | 43 | // Initialization code 44 | _crashLogs = [[UITextView alloc] initWithFrame:CGRectMake(0, 44 , frame.size.width, frame.size.height-44)]; 45 | _crashLogs.font = [UIFont fontWithName:@"Courier-Bold" size:14]; 46 | _crashLogs.textColor = [UIColor orangeColor]; 47 | _crashLogs.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6f];; 48 | _crashLogs.indicatorStyle = 0; 49 | _crashLogs.editable = NO; 50 | _crashLogs.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 51 | _crashLogs.layer.borderColor = [UIColor colorWithWhite:0.5f alpha:1.0f].CGColor; 52 | _crashLogs.layer.borderWidth = 2.0f; 53 | [self addSubview:_crashLogs]; 54 | 55 | } 56 | return self; 57 | } 58 | 59 | - (void)setPath:(NSString *)path 60 | { 61 | _path = path; 62 | 63 | NSDictionary* logs = [[VZCrashInspector sharedInstance] crashForKey:path]; 64 | 65 | NSString* header = @"crashes comes from => VZCrashInspector"; 66 | header = [header stringByAppendingString:@"\n--------------------------------------\n"]; 67 | _crashLogs.text = header; 68 | 69 | if (logs) { 70 | 71 | NSString* date = logs[@"date"]; 72 | _crashLogs.text = [_crashLogs.text stringByAppendingString:[[@"> date :"stringByAppendingString:date] stringByAppendingString:@"\n"]]; 73 | 74 | NSDictionary* info = logs[@"info"]; 75 | 76 | //reason 77 | NSString* reason = info[@"reason"]; 78 | _crashLogs.text = [[[_crashLogs.text stringByAppendingString:@"> reason: "] stringByAppendingString:reason] stringByAppendingString:@"\n"]; 79 | 80 | //name 81 | NSString* name = info[@"name"]; 82 | _crashLogs.text = [[[_crashLogs.text stringByAppendingString:@"> name: "] stringByAppendingString:name] stringByAppendingString:@"\n"]; 83 | 84 | //call stack 85 | NSArray* callStack = info[@"callStack"]; 86 | _crashLogs.text = [[[_crashLogs.text stringByAppendingString:@"> callStack: \n"] stringByAppendingString:[NSString stringWithFormat:@"%@",callStack]] stringByAppendingString:@"\n"]; 87 | 88 | } 89 | } 90 | 91 | - (void)onBack 92 | { 93 | if (self.delegate) { 94 | [self.delegate onBack]; 95 | } 96 | } 97 | 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /VZInspector/toolbox/framerate/VZFrameRateOverlay.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZFrameRateOverlay : UIWindow 8 | 9 | +(instancetype)sharedInstance; 10 | +(void)start; 11 | +(void)stop; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /VZInspector/toolbox/framerate/VZFrameRateOverlay.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZFrameRateOverlay.h" 6 | #import "VZInspector.h" 7 | #import "VZInspectorResource.h" 8 | #import "VZInspectorOverlay.h" 9 | 10 | #define kVZHistoryTimeStampLength 42 11 | 12 | @interface VZFrameRateOverlay () 13 | @property (nonatomic, strong) CADisplayLink *displayLink; 14 | @property (nonatomic, strong) UILabel *frameRateLabel; 15 | @property (nonatomic, assign) CFTimeInterval lastTimeStamp; 16 | @property (nonatomic, assign) CFTimeInterval *historyTimeStamp; 17 | @end 18 | 19 | @implementation VZFrameRateOverlay 20 | 21 | + (instancetype)sharedInstance { 22 | static VZFrameRateOverlay* instance = nil; 23 | static dispatch_once_t onceToken; 24 | 25 | dispatch_once(&onceToken, ^{ 26 | int x = [UIScreen mainScreen].bounds.size.width > 320 ? 250 :180 ; 27 | instance = [[VZFrameRateOverlay alloc] initWithFrame:CGRectMake(x + 15, 0, 60, 20)]; 28 | }); 29 | 30 | return instance; 31 | } 32 | 33 | + (void)start { 34 | [VZInspectorOverlay sharedInstance].hidden = YES; 35 | 36 | VZFrameRateOverlay* o = [self sharedInstance]; 37 | o.tag = 100; 38 | o.windowLevel = UIWindowLevelStatusBar+1; 39 | o.hidden = NO; 40 | 41 | o.displayLink.paused = NO; 42 | } 43 | 44 | + (void)stop { 45 | VZFrameRateOverlay* o = [self sharedInstance]; 46 | o.hidden = YES; 47 | 48 | [VZInspectorOverlay sharedInstance].hidden = NO; 49 | 50 | o.displayLink.paused = YES; 51 | } 52 | 53 | - (id)initWithFrame:(CGRect)frame { 54 | self = [super initWithFrame:frame]; 55 | 56 | if (self) { 57 | self.backgroundColor = [UIColor clearColor]; 58 | 59 | _lastTimeStamp = CACurrentMediaTime(); 60 | _historyTimeStamp = malloc(sizeof(CFTimeInterval) * kVZHistoryTimeStampLength); 61 | 62 | _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick:)]; 63 | [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 64 | _displayLink.paused = YES; 65 | 66 | _frameRateLabel = [[UILabel alloc] initWithFrame:self.bounds]; 67 | _frameRateLabel.font = [UIFont systemFontOfSize:12.f]; 68 | _frameRateLabel.textColor = [UIColor orangeColor]; 69 | _frameRateLabel.userInteractionEnabled = true; 70 | [_frameRateLabel addGestureRecognizer:[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(onSelfClicked:)]]; 71 | [self addSubview:_frameRateLabel]; 72 | 73 | [[NSNotificationCenter defaultCenter] addObserver: self 74 | selector: @selector(applicationDidBecomeActiveNotification) 75 | name: UIApplicationDidBecomeActiveNotification 76 | object: nil]; 77 | 78 | [[NSNotificationCenter defaultCenter] addObserver: self 79 | selector: @selector(applicationWillResignActiveNotification) 80 | name: UIApplicationWillResignActiveNotification 81 | object: nil]; 82 | } 83 | 84 | return self; 85 | } 86 | 87 | - (void)applicationDidBecomeActiveNotification { 88 | if (!self.hidden) { 89 | [_displayLink setPaused:NO]; 90 | } 91 | } 92 | 93 | - (void)applicationWillResignActiveNotification { 94 | if (!self.hidden) { 95 | [_displayLink setPaused:YES]; 96 | } 97 | } 98 | 99 | - (void)displayLinkTick:(CADisplayLink *)displayLink { 100 | CFTimeInterval frameInterval = displayLink.timestamp - self.lastTimeStamp; 101 | NSUInteger totalCount = 0; 102 | CFTimeInterval totalInterval = 0; 103 | 104 | for (NSUInteger i = kVZHistoryTimeStampLength - 1; i > 0; i--) { 105 | self.historyTimeStamp[i] = self.historyTimeStamp[i - 1]; 106 | totalCount++; 107 | totalInterval += self.historyTimeStamp[i - 1]; 108 | } 109 | self.historyTimeStamp[0] = frameInterval; 110 | totalCount++; 111 | totalInterval += frameInterval; 112 | 113 | self.lastTimeStamp = displayLink.timestamp; 114 | 115 | self.frameRateLabel.text = [NSString stringWithFormat:@"%.ffps", 1 / (totalInterval / totalCount)]; 116 | } 117 | 118 | - (void)onSelfClicked:(UILabel *)sender { 119 | if([VZInspector isShow]) 120 | [VZInspector hide]; 121 | else 122 | [VZInspector show]; 123 | } 124 | 125 | - (void)becomeKeyWindow { 126 | //fix keywindow problem: 127 | //UIActionSheet在close后回重置keywindow,防止自己被设成keywindow 128 | [[[UIApplication sharedApplication].delegate window] makeKeyWindow]; 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /VZInspector/toolbox/grid/UIWindow+VZInspector.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface UIWindow (VZInspector) 8 | 9 | + (BOOL)isSwizzled; 10 | + (void)blockEvent:(BOOL) b; 11 | + (void)swizzle:(BOOL)b; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /VZInspector/toolbox/grid/UIWindow+VZInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "UIWindow+VZInspector.h" 6 | #include 7 | #include 8 | #include 9 | #import "VZInspectorOverlay.h" 10 | 11 | 12 | static bool g_blockEvent = false; 13 | static bool g_swizzled = false; 14 | static void (*g_sendEvent)(id,SEL,UIEvent* ); 15 | 16 | 17 | 18 | @implementation UIWindow (VZInspector) 19 | 20 | + (BOOL)isSwizzled 21 | { 22 | UIWindow* keywindow = [UIApplication sharedApplication].keyWindow; 23 | 24 | if (keywindow == self) 25 | { 26 | return g_swizzled; 27 | } 28 | return NO; 29 | } 30 | + (void)blockEvent:(BOOL) b 31 | { 32 | g_blockEvent = b; 33 | } 34 | 35 | + (void)swizzle:(BOOL)b 36 | { 37 | g_swizzled = b; 38 | 39 | Method imp = class_getInstanceMethod([UIWindow class], @selector(sendEvent:)); 40 | 41 | if (b) { 42 | g_sendEvent = (void* )class_getMethodImplementation([UIWindow class],@selector(sendEvent:)); 43 | } 44 | 45 | IMP swizzleMethod = class_getMethodImplementation([UIWindow class], @selector(swizzle_SendEvent:)); 46 | 47 | 48 | if (b) { 49 | method_setImplementation(imp, swizzleMethod); 50 | } 51 | else 52 | { 53 | method_setImplementation(imp, (IMP)g_sendEvent); 54 | } 55 | 56 | } 57 | 58 | - (void)swizzle_SendEvent:(UIEvent* )event 59 | { 60 | switch (event.type) 61 | { 62 | case UIEventTypeTouches: 63 | { 64 | NSSet * allTouches = [event allTouches]; 65 | 66 | if ( 1 == [allTouches count] ) 67 | { 68 | UITouch* touch = [allTouches allObjects][0]; 69 | 70 | if (touch.tapCount == 1) 71 | { 72 | UIWindow* appWnd = [UIApplication sharedApplication].delegate.window; 73 | 74 | if (appWnd == self) 75 | { 76 | switch (touch.phase) { 77 | 78 | case UITouchPhaseBegan: 79 | { 80 | //NSLog( @"view '%@', touch began\n%@", [[touch.view class] description], [touch.view description] ); 81 | 82 | UIView* border = [[UIView alloc]initWithFrame:CGRectMake(0, 0, touch.view.bounds.size.width, touch.view.bounds.size.height)]; 83 | border.layer.borderColor = [UIColor redColor].CGColor; 84 | border.layer.borderWidth = 2.0f; 85 | border.layer.backgroundColor = [UIColor clearColor].CGColor; 86 | border.alpha = 0.8f; 87 | [touch.view addSubview:border]; 88 | 89 | 90 | UILabel* label = [[UILabel alloc]initWithFrame:CGRectMake(0, 5, touch.view.bounds.size.width-10, 10)]; 91 | label.text = [NSString stringWithFormat:@"[%.0f,%.0f,%.0f,%.0f]",touch.view.frame.origin.x, 92 | touch.view.frame.origin.y, 93 | touch.view.frame.size.width, 94 | touch.view.frame.size.height]; 95 | label.textAlignment = NSTextAlignmentRight; 96 | label.textColor = [UIColor redColor]; 97 | label.font = [UIFont systemFontOfSize:10.0f]; 98 | label.backgroundColor = [UIColor clearColor]; 99 | [touch.view addSubview:label]; 100 | 101 | [UIView animateWithDuration:0.8 animations:^{ 102 | 103 | border.alpha = 0.0f; 104 | label.alpha = 0.0f; 105 | 106 | 107 | } completion:^(BOOL finished) { 108 | 109 | [border removeFromSuperview]; 110 | [label removeFromSuperview]; 111 | 112 | 113 | }]; 114 | 115 | 116 | break; 117 | } 118 | case UITouchPhaseMoved: 119 | { 120 | break; 121 | } 122 | 123 | case UITouchPhaseEnded: 124 | case UITouchPhaseCancelled: 125 | { 126 | 127 | break; 128 | 129 | } 130 | default: 131 | break; 132 | }//end of switch 133 | }//end of if 134 | else 135 | { 136 | [[self class] swizzle:NO]; 137 | 138 | CGPoint pt = [touch locationInView:self]; 139 | 140 | //show debugger:todo 141 | if (CGRectContainsPoint([VZInspectorOverlay sharedInstance].frame, pt)) { 142 | [[VZInspectorOverlay sharedInstance] sendEvent:event]; 143 | } 144 | } 145 | }//end of if 146 | 147 | }//end of if 148 | 149 | break; 150 | }//end of case 151 | default: 152 | break; 153 | }//end of switch 154 | 155 | //pass event 156 | if (!g_blockEvent && g_sendEvent) { 157 | g_sendEvent(self,_cmd,event); 158 | } 159 | } 160 | 161 | @end 162 | -------------------------------------------------------------------------------- /VZInspector/toolbox/grid/VZInspectorGridView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @interface VZInspectorGridView : VZInspectorView 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /VZInspector/toolbox/grid/VZInspectorGridView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #include 6 | #import "VZInspectorGridView.h" 7 | #import "VZInspectorWindow.h" 8 | 9 | @implementation VZInspectorGridView 10 | 11 | - (id)initWithFrame:(CGRect)frame 12 | { 13 | self = [super initWithFrame:frame]; 14 | if (self) { 15 | // Initialization code 16 | self.backgroundColor = [UIColor clearColor]; 17 | //self.userInteractionEnabled = YES; 18 | 19 | UIButton* btn = [[UIButton alloc]initWithFrame:CGRectMake(300, 0, 20, 20)]; 20 | btn.backgroundColor = [UIColor clearColor]; 21 | btn.layer.cornerRadius = 10; 22 | btn.layer.masksToBounds = YES; 23 | btn.layer.borderColor = [UIColor redColor].CGColor; 24 | btn.layer.borderWidth = 1.0f; 25 | [btn setTitle:@"X" forState:UIControlStateNormal]; 26 | [btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; 27 | [btn addTarget:self action:@selector(onClicked:) forControlEvents:UIControlEventTouchUpInside]; 28 | [self addSubview:btn]; 29 | 30 | } 31 | return self; 32 | } 33 | 34 | 35 | - (BOOL)canTouchPassThrough:(CGPoint)pt { 36 | return pt.y > 20; 37 | } 38 | 39 | 40 | - (void)drawRect:(CGRect)rect 41 | { 42 | 43 | // Drawing code 44 | CGContextRef context = UIGraphicsGetCurrentContext(); 45 | 46 | //横线: 47 | int h = [UIScreen mainScreen].bounds.size.height; 48 | int w = [UIScreen mainScreen].bounds.size.width; 49 | 50 | for (int i=0; i<=h/20; i++) { 51 | 52 | [self drawSingleLine:context :(CGPoint){0, (i)*20} :(CGPoint){w,(i)*20} :[UIColor cyanColor] :0.5f]; 53 | 54 | if (i%2 == 0) { 55 | 56 | NSString* str = [NSString stringWithFormat:@"%d",i*20]; 57 | 58 | [[UIColor cyanColor] set]; 59 | [str drawAtPoint:CGPointMake(0, (i*20)) withFont:[UIFont systemFontOfSize:8.0f]]; 60 | } 61 | } 62 | 63 | //竖线: 64 | for (int i=0; i<=w/20; i++) { 65 | 66 | [self drawSingleLine:context :(CGPoint){i*20,0} :(CGPoint){i*20,h} :[UIColor cyanColor] : 0.5f]; 67 | 68 | if (i % 2 == 0) { 69 | NSString* str = [NSString stringWithFormat:@"%d",i*20]; 70 | 71 | [[UIColor cyanColor] set]; 72 | [str drawAtPoint:CGPointMake((i*20),0) withFont:[UIFont systemFontOfSize:8.0f]]; 73 | 74 | } 75 | } 76 | } 77 | 78 | 79 | - (void)onClicked:(id)sender 80 | { 81 | 82 | #pragma clang diagnostic push 83 | #pragma clang diagnostic ignored "-Wundeclared-selector" 84 | [self.parentViewController performSelector:@selector(onBack) withObject:nil]; 85 | #pragma clang diagnostic pop 86 | 87 | } 88 | 89 | //draw a line 90 | - (void) drawSingleLine:(CGContextRef)context :(CGPoint) startPt :(CGPoint) endPt :(UIColor*) strokeColor :(CGFloat) strokeLineWidth 91 | { 92 | //CGFloat delta = strokeLineWidth/2; 93 | //CGFloat delta = 0; 94 | 95 | CGContextSaveGState(context); 96 | CGContextSetLineCap(context, kCGLineCapSquare); 97 | CGContextSetStrokeColorWithColor(context, strokeColor.CGColor); 98 | CGContextSetLineWidth(context, strokeLineWidth); 99 | CGContextSetShouldAntialias(context, NO ); 100 | // CGContextMoveToPoint(context, startPt.x + delta, startPt.y + delta); 101 | // CGContextAddLineToPoint(context, endPt.x - delta, endPt.y - delta); 102 | CGContextMoveToPoint(context, startPt.x+0.5, startPt.y+0.5); 103 | CGContextAddLineToPoint(context, endPt.x+0.5, endPt.y+0.5); 104 | CGContextStrokePath(context); 105 | CGContextRestoreGState(context); 106 | } 107 | 108 | 109 | - (void)willMoveToWindow:(UIWindow *)newWindow 110 | { 111 | [super willMoveToWindow:newWindow]; 112 | 113 | if ([self.parentViewController valueForKey:@"topView"] != self ) { 114 | 115 | // [UIWindow swizzle:YES]; 116 | // [UIWindow blockEvent:YES]; 117 | // [ETDebuggerWindow sharedInstance].backgroundColor = [UIColor clearColor]; 118 | // [ETDebuggerWindow sharedInstance].alpha = 1.0f; 119 | [VZInspectorWindow sharedInstance].backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.3f]; 120 | } 121 | else 122 | { 123 | // [UIWindow swizzle:NO]; 124 | // [UIWindow blockEvent:NO]; 125 | [VZInspectorWindow sharedInstance].backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6f]; 126 | } 127 | 128 | } 129 | 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /VZInspector/toolbox/image/VZInspectorImageInfoView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @interface VZInspectorImageInfoView : VZInspectorView 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /VZInspector/toolbox/location/CLLocationManager+FLFake.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface CLLocationManager (FLFake) 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /VZInspector/toolbox/location/CLLocationManager+FLFake.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "CLLocationManager+FLFake.h" 6 | #import 7 | #import "VZDefine.h" 8 | #import "FLFakeConfig.h" 9 | 10 | @implementation CLLocationManager (FLFake) 11 | 12 | + (void)load { 13 | Method originMethod = class_getInstanceMethod([CLLocationManager class], @selector(startUpdatingLocation)); 14 | Method swizzleMethod = class_getInstanceMethod([CLLocationManager class], @selector(fl_startUpdatingLocation)); 15 | method_exchangeImplementations(originMethod, swizzleMethod); 16 | } 17 | 18 | - (void)fl_startUpdatingLocation { 19 | NSLog(@"Start updating location"); 20 | FLFakeConfig *fakeConfig = [FLFakeConfig sharedInstance]; 21 | if (fakeConfig.enabled) { 22 | if (self.delegate) { 23 | if (!fequalzero(fakeConfig.delay)) { 24 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(fakeConfig.delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 25 | [self updateLocation:fakeConfig.location]; 26 | }); 27 | } else { 28 | [self updateLocation:fakeConfig.location]; 29 | } 30 | } 31 | } else { 32 | [self fl_startUpdatingLocation]; 33 | } 34 | } 35 | 36 | - (void)updateLocation:(CLLocation *)location { 37 | if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) { 38 | [self.delegate locationManager:self didUpdateLocations:@[location]]; 39 | } else if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateToLocation:fromLocation:)]) { 40 | [self.delegate locationManager:self didUpdateToLocation:location fromLocation:location]; 41 | } 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /VZInspector/toolbox/location/FLFakeConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | @interface FLFakeConfig : NSObject 9 | 10 | @property (nonatomic, assign) BOOL enabled; 11 | @property (nonatomic, readonly) CLLocation *location; 12 | @property (nonatomic, assign) CFTimeInterval delay; 13 | 14 | - (void)setLatitude:(CLLocationDegrees)latitude; 15 | - (void)setLongitude:(CLLocationDegrees)longitude; 16 | 17 | + (instancetype)sharedInstance; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /VZInspector/toolbox/location/FLFakeConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "FLFakeConfig.h" 6 | #import "VZDefine.h" 7 | 8 | @interface FLFakeConfig () 9 | 10 | @property (nonatomic, strong) NSUserDefaults *userDefaults; 11 | 12 | @end 13 | 14 | static NSString * const kFLEnable = @"FLEnable"; 15 | static NSString * const kFLLatitude = @"FLLatitude"; 16 | static NSString * const kFLLongitude = @"FLLongitude"; 17 | static NSString * const kFLDelay = @"FLDelay"; 18 | 19 | @implementation FLFakeConfig 20 | 21 | + (instancetype)sharedInstance { 22 | static FLFakeConfig *instance; 23 | static dispatch_once_t onceToken; 24 | dispatch_once(&onceToken, ^{ 25 | instance = [[self alloc] init]; 26 | }); 27 | return instance; 28 | } 29 | 30 | - (instancetype)init { 31 | self = [super init]; 32 | if (self) { 33 | _userDefaults = [[NSUserDefaults alloc]initWithUser:@"com.johnwong.FakeLocation"]; 34 | } 35 | return self; 36 | } 37 | 38 | - (void)setEnabled:(BOOL)enabled { 39 | [_userDefaults setValue:@(enabled) forKey:kFLEnable]; 40 | [_userDefaults synchronize]; 41 | } 42 | 43 | - (void)setLatitude:(CLLocationDegrees)latitude { 44 | [_userDefaults setValue:@(latitude) forKey:kFLLatitude]; 45 | [_userDefaults synchronize]; 46 | } 47 | 48 | - (void)setLongitude:(CLLocationDegrees)longitude { 49 | [_userDefaults setValue:@(longitude) forKey:kFLLongitude]; 50 | [_userDefaults synchronize]; 51 | } 52 | 53 | - (void)setDelay:(CFTimeInterval)delay { 54 | [_userDefaults setValue:@(delay) forKey:kFLDelay]; 55 | [_userDefaults synchronize]; 56 | } 57 | 58 | - (BOOL)enabled { 59 | id value = [_userDefaults valueForKey:kFLEnable]; 60 | return value? [value boolValue] : NO; 61 | } 62 | 63 | - (CLLocation *)location { 64 | CLLocationDegrees latitude = [[_userDefaults valueForKey:kFLLatitude] doubleValue]; 65 | CLLocationDegrees longitude = [[_userDefaults valueForKey:kFLLongitude] doubleValue]; 66 | if (fequalzero(latitude) && fequalzero(longitude)) { 67 | latitude = 30.26667; 68 | longitude = 120.2; 69 | } 70 | return [[CLLocation alloc] initWithLatitude:latitude longitude:longitude]; 71 | } 72 | 73 | - (CFTimeInterval)delay { 74 | return [[_userDefaults valueForKey:kFLDelay] doubleValue]; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /VZInspector/toolbox/location/VZInspectorLocationView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @interface VZInspectorLocationView : VZInspectorView 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZInspectorNetworkDetailView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @protocol VZInspectorNetworkDetailView 8 | 9 | - (void)onDetailBack; 10 | @end 11 | 12 | @class VZNetworkTransaction; 13 | @interface VZInspectorNetworkDetailView : UIView 14 | 15 | @property(nonatomic,strong) VZNetworkTransaction* transaction; 16 | @property(nonatomic,weak) id delegate; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZInspectorNetworkHistoryView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @interface VZInspectorNetworkHistoryView : VZInspectorView 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZNetworkInspector.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import "VZNetworkTransaction.h" 7 | 8 | extern NSString* const kVZNetworkInspectorRequestNotification; 9 | extern NSString* const kVZNetworkInspectorRequestFinishedNotification; 10 | 11 | typedef NSString *(^TransactionTitleFilter)(VZNetworkTransaction *transaction); 12 | typedef NSString *(^VZNetworkDecoder)(VZNetworkTransaction *transaction, NSData *data); 13 | 14 | @interface VZNetworkInspector : NSObject 15 | + (instancetype)sharedInstance; 16 | 17 | @property(nonatomic,assign) size_t totalResponseBytes; 18 | @property(nonatomic,assign) NSInteger totalNetworkCount; 19 | 20 | - (void)addTransactionTitleFilter:(TransactionTitleFilter)filter; 21 | - (NSArray *)transactionTitleFilters; 22 | + (void)setIgnoreDelegateClasses:(NSSet *)classes; 23 | 24 | - (void)addRequestDecoder:(VZNetworkDecoder)decoder; 25 | - (void)addResponseDecoder:(VZNetworkDecoder)decoder; 26 | 27 | @property (nonatomic, strong, readonly) NSMutableArray *requestDecoders; 28 | @property (nonatomic, strong, readonly) NSMutableArray *responseDecoders; 29 | 30 | - (NSString *)decodeRequestData:(NSData *)data withTransaction:(VZNetworkTransaction *)transaction; 31 | - (NSString *)decodeResponseData:(NSData *)data withTransaction:(VZNetworkTransaction *)transaction; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZNetworkInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZNetworkInspector.h" 6 | #import "NSObject+VZInspector.h" 7 | #import "VZLogInspector.h" 8 | #import "VZNetworkObserver.h" 9 | 10 | 11 | NSString* const kVZNetworkInspectorRequestNotification = @"VZNetworkInspectorRequestNotification"; 12 | NSString* const kVZNetworkInspectorRequestFinishedNotification = @"VZNetworkInspectorRequestFinishedNotification"; 13 | 14 | 15 | @interface VZNetworkInspector() 16 | 17 | @property(nonatomic,assign) NSInteger networkCount; 18 | 19 | @end 20 | 21 | @implementation VZNetworkInspector { 22 | NSMutableArray *_titleFilters; 23 | } 24 | 25 | + (instancetype)sharedInstance 26 | { 27 | static VZNetworkInspector* instance; 28 | static dispatch_once_t onceToken; 29 | dispatch_once(&onceToken, ^{ 30 | instance = [VZNetworkInspector new]; 31 | }); 32 | return instance; 33 | } 34 | 35 | - (id)init 36 | { 37 | self = [super init]; 38 | 39 | if (self) { 40 | _titleFilters = [NSMutableArray array]; 41 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onRequestReceived:) name:kVZNetworkInspectorRequestNotification object:nil]; 42 | 43 | _requestDecoders = [NSMutableArray array]; 44 | _responseDecoders = [NSMutableArray array]; 45 | 46 | } 47 | return self; 48 | } 49 | 50 | - (void)dealloc 51 | { 52 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 53 | } 54 | 55 | - (void)onRequestReceived:(NSNotification* )notify 56 | { 57 | self.totalNetworkCount ++ ; 58 | self.networkCount ++; 59 | 60 | if (self.samplePoints == nil) 61 | self.samplePoints = [NSMutableArray new]; 62 | 63 | [self.samplePoints addObject:@(self.networkCount)]; 64 | [self.samplePoints addObject:@(self.networkCount)]; 65 | 66 | self.networkCount --; 67 | [self.samplePoints addObject:@(self.networkCount)]; 68 | [self.samplePoints addObject:@(self.networkCount)]; 69 | 70 | 71 | NSNumber* len = notify.userInfo[@"data-len"]; 72 | self.totalResponseBytes += len.longValue; 73 | } 74 | 75 | - (void)onRequestFinished:(NSNotification* )notify 76 | { 77 | 78 | } 79 | 80 | 81 | //////////////////////////////////////////////////////////////////////////////////////////////////////////// 82 | #pragma mark - for debugger use 83 | 84 | - (void)vz_heartBeat 85 | { 86 | 87 | if (self.samplePoints == nil) 88 | self.samplePoints = [NSMutableArray new]; 89 | 90 | // NSLog(@"request:%d",self.networkCount); 91 | 92 | [self.samplePoints addObject:@(self.networkCount)]; 93 | 94 | //keep last 50 points 95 | if ( [self.samplePoints count] > 50 ) 96 | { 97 | NSRange range; 98 | range.location = 0; 99 | range.length = [self.samplePoints count] - 50; 100 | [self.samplePoints removeObjectsInRange:range]; 101 | } 102 | 103 | } 104 | 105 | - (void)addTransactionTitleFilter:(TransactionTitleFilter)filter 106 | { 107 | [_titleFilters addObject:filter]; 108 | } 109 | 110 | - (NSArray *)transactionTitleFilters 111 | { 112 | return [_titleFilters copy]; 113 | } 114 | 115 | + (void)setIgnoreDelegateClasses:(NSSet *)classes 116 | { 117 | [VZNetworkObserver setIgnoreDelegateClasses:classes]; 118 | } 119 | 120 | - (void)addRequestDecoder:(VZNetworkDecoder)decoder 121 | { 122 | if (decoder) { 123 | [_requestDecoders addObject:decoder]; 124 | } 125 | } 126 | 127 | - (void)addResponseDecoder:(VZNetworkDecoder)decoder 128 | { 129 | if (decoder) { 130 | [_responseDecoders addObject:decoder]; 131 | } 132 | } 133 | 134 | - (NSString *)decodeRequestData:(NSData *)data withTransaction:(VZNetworkTransaction *)transaction 135 | { 136 | for (VZNetworkDecoder decoder in [VZNetworkInspector sharedInstance].requestDecoders) { 137 | NSString *result = decoder(transaction, data); 138 | if (result.length > 0) { 139 | return result; 140 | } 141 | } 142 | return nil; 143 | } 144 | 145 | - (NSString *)decodeResponseData:(NSData *)data withTransaction:(VZNetworkTransaction *)transaction 146 | { 147 | for (VZNetworkDecoder decoder in [VZNetworkInspector sharedInstance].responseDecoders) { 148 | NSString *result = decoder(transaction, data); 149 | if (result.length > 0) { 150 | return result; 151 | } 152 | } 153 | return nil; 154 | } 155 | 156 | @end 157 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZNetworkInspectorOverView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | // 5 | //#import 6 | // 7 | //@interface VZNetworkInspectorOverView : UIView 8 | // 9 | //- (void)handleRead; 10 | //- (void)handleWrite; 11 | // 12 | //@end 13 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZNetworkInspectorOverView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | // 5 | //#include 6 | //#import "VZNetworkInspectorOverView.h" 7 | //#import "VZInspectorPlotView.h" 8 | //#import "NSObject+VZInspector.h" 9 | //#import "VZNetworkInspector.h" 10 | // 11 | // 12 | // 13 | //@implementation VZNetworkInspectorOverView 14 | //{ 15 | // UILabel * _titleView; 16 | // UILabel * _statusView; 17 | // VZInspectorPlotView* _plotView1; 18 | //} 19 | // 20 | //- (id)initWithFrame:(CGRect)frame 21 | //{ 22 | // self = [super initWithFrame:frame]; 23 | // if (self) { 24 | // 25 | // //self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6f]; 26 | // self.layer.borderColor = [UIColor colorWithWhite:0.5f alpha:1.0f].CGColor; 27 | // self.layer.borderWidth = 1.0f; 28 | // 29 | // CGRect plotFrame; 30 | // plotFrame.size.width = frame.size.width; 31 | // plotFrame.size.height = frame.size.height - 20.0f; 32 | // plotFrame.origin.x = 0.0f; 33 | // plotFrame.origin.y = 20.0f; 34 | // 35 | // //draw http connection pool 36 | // _plotView1 = [[VZInspectorPlotView alloc] initWithFrame:plotFrame]; 37 | // _plotView1.alpha = 0.6f; 38 | // _plotView1.lowerBound = 0.0f; 39 | // _plotView1.upperBound = 0.0f; 40 | // _plotView1.lineColor = [UIColor yellowColor]; 41 | // _plotView1.lineWidth = 2.0f; 42 | // _plotView1.capacity = 50; 43 | // _plotView1.fill = NO; 44 | // [self addSubview:_plotView1]; 45 | // 46 | // 47 | // CGRect titleFrame; 48 | // titleFrame.size.width = 120.0f; 49 | // titleFrame.size.height = 20.0f; 50 | // titleFrame.origin.x = 8.0f; 51 | // titleFrame.origin.y = 0.0f; 52 | // 53 | // _titleView = [[UILabel alloc] initWithFrame:titleFrame]; 54 | // _titleView.textColor = [UIColor orangeColor]; 55 | // _titleView.textAlignment = NSTextAlignmentLeft; 56 | // _titleView.font = [UIFont boldSystemFontOfSize:12.0f]; 57 | // _titleView.lineBreakMode = NSLineBreakByClipping; 58 | // _titleView.backgroundColor = [UIColor clearColor]; 59 | // _titleView.numberOfLines = 1; 60 | // _titleView.text = @"Network"; 61 | // [self addSubview:_titleView]; 62 | // 63 | // CGRect statusFrame; 64 | // statusFrame.size.width = 200; 65 | // statusFrame.size.height = 20.0f; 66 | // statusFrame.origin.x = frame.size.width - 200 -10; 67 | // statusFrame.origin.y = 0.0f; 68 | // 69 | // _statusView = [[UILabel alloc] initWithFrame:statusFrame]; 70 | // _statusView.textColor = [UIColor whiteColor]; 71 | // _statusView.textAlignment = NSTextAlignmentRight; 72 | // _statusView.font = [UIFont boldSystemFontOfSize:12.0f]; 73 | // _statusView.lineBreakMode = NSLineBreakByClipping; 74 | // _statusView.numberOfLines = 1; 75 | // _statusView.backgroundColor = [UIColor clearColor]; 76 | // [self addSubview:_statusView]; 77 | // 78 | // } 79 | // return self; 80 | //} 81 | // 82 | //- (void)handleRead 83 | //{ 84 | // [[VZNetworkInspector sharedInstance] vz_heartBeat]; 85 | //} 86 | //- (void)handleWrite 87 | //{ 88 | // [self writeHeartBeat]; 89 | //} 90 | // 91 | //- (void)writeHeartBeat 92 | //{ 93 | // 94 | // NSMutableString * text = [NSMutableString string]; 95 | // [text appendFormat:@"Count: %ld",(long)[VZNetworkInspector sharedInstance].totalNetworkCount]; 96 | // [text appendFormat:@" Bytes:%@ ",[self number2String:[VZNetworkInspector sharedInstance].totalResponseBytes]]; 97 | // 98 | // _statusView.text = text; 99 | // 100 | // //http connection pool 101 | // NSArray* tmp2 = [VZNetworkInspector sharedInstance].samplePoints.copy; 102 | // CGFloat _upperBound2 = 1; 103 | // CGFloat _lowerBound2 = 0; 104 | // 105 | // for ( NSNumber * n in tmp2 ) 106 | // { 107 | // if ( n.intValue > _upperBound2 ) 108 | // { 109 | // _upperBound2 = n.intValue; 110 | // if ( _upperBound2 < _lowerBound2 ) 111 | // { 112 | // _lowerBound2 = _upperBound2; 113 | // } 114 | // } 115 | // else if ( n.intValue < _lowerBound2 ) 116 | // { 117 | // _lowerBound2 = n.intValue; 118 | // } 119 | // } 120 | // 121 | // [_plotView1 setPlots:tmp2]; 122 | // [_plotView1 setLowerBound:_lowerBound2]; 123 | // [_plotView1 setUpperBound:_upperBound2]; 124 | // [_plotView1 setNeedsDisplay]; 125 | // 126 | //} 127 | //#define KB (1024) 128 | //#define MB (KB * 1024) 129 | //#define GB (MB * 1024) 130 | // 131 | //- (NSString* )number2String:(int64_t)n 132 | //{ 133 | // if ( n < KB ) 134 | // { 135 | // return [NSString stringWithFormat:@"%lldB", n]; 136 | // } 137 | // else if ( n < MB ) 138 | // { 139 | // return [NSString stringWithFormat:@"%.1fK", (float)n / (float)KB]; 140 | // } 141 | // else if ( n < GB ) 142 | // { 143 | // return [NSString stringWithFormat:@"%.1fM", (float)n / (float)MB]; 144 | // } 145 | // else 146 | // { 147 | // return [NSString stringWithFormat:@"%.1fG", (float)n / (float)GB]; 148 | // } 149 | //} 150 | // 151 | // 152 | //@end 153 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZNetworkObserver.h: -------------------------------------------------------------------------------- 1 | // 2 | // VZNetworkObserver.h 3 | // Derived from: 4 | // 5 | // FLEXNetworkObserver 6 | // Flipboard 7 | // 8 | // Created by Ryan Olson 9 | // Copyright (c) 2015 Flipboard. All rights reserved. 10 | // 11 | 12 | 13 | 14 | #import 15 | 16 | extern NSString *const kVZNetworkObserverEnabledStateChangedNotification; 17 | 18 | 19 | @interface VZNetworkObserver : NSObject 20 | 21 | 22 | + (void)setEnabled:(BOOL)enabled; 23 | + (BOOL)isEnabled; 24 | 25 | + (void)setShouldEnableOnLaunch:(BOOL)shouldEnableOnLaunch; 26 | + (BOOL)shouldEnableOnLaunch; 27 | + (void)setIgnoreDelegateClasses:(NSSet *)classes; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZNetworkRecorder.h: -------------------------------------------------------------------------------- 1 | // 2 | // VZNetworkObserver.h 3 | // Derived from: 4 | // Flipboard 5 | // 6 | // Created by Ryan Olson on 2/4/15. 7 | // Copyright (c) 2015 Flipboard. All rights reserved. 8 | // 9 | 10 | #import 11 | 12 | 13 | @class VZNetworkTransaction; 14 | 15 | 16 | @interface VZNetworkRecorder : NSObject 17 | 18 | 19 | /// In general, it only makes sense to have one recorder for the entire application. 20 | + (instancetype)defaultRecorder; 21 | 22 | /// Defaults to 25 MB if never set. Values set here are presisted across launches of the app. 23 | @property (nonatomic, assign) NSUInteger responseCacheByteLimit; 24 | 25 | /// If NO, the recorder not cache will not cache response for content types with an "image", "video", or "audio" prefix. 26 | @property (nonatomic, assign) BOOL shouldCacheMediaResponses; 27 | 28 | // Accessing recorded network activity 29 | 30 | /// Array of VZNetworkTransaction objects ordered by start time with the newest first. 31 | - (NSArray *)networkTransactions; 32 | 33 | /// The full response data IFF it hasn't been purged due to memory pressure. 34 | - (NSData *)cachedResponseBodyForTransaction:(VZNetworkTransaction *)transaction; 35 | 36 | /// Dumps all network transactions and cached response bodies. 37 | - (void)clearRecordedActivity; 38 | 39 | 40 | // Recording network activity 41 | 42 | /// Call when app is about to send HTTP request. 43 | - (void)recordRequestWillBeSentWithRequestID:(NSString *)requestID request:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse; 44 | 45 | /// Call when HTTP response is available. 46 | - (void)recordResponseReceivedWithRequestID:(NSString *)requestID response:(NSURLResponse *)response; 47 | 48 | /// Call when data chunk is received over the network. 49 | - (void)recordDataReceivedWithRequestID:(NSString *)requestID dataLength:(int64_t)dataLength; 50 | 51 | /// Call when HTTP request has finished loading. 52 | - (void)recordLoadingFinishedWithRequestID:(NSString *)requestID responseBody:(NSData *)responseBody; 53 | 54 | /// Call when HTTP request has failed to load. 55 | - (void)recordLoadingFailedWithRequestID:(NSString *)requestID error:(NSError *)error; 56 | 57 | /// Call to set the request mechanism anytime after recordRequestWillBeSent... has been called. 58 | /// This string can be set to anything useful about the API used to make the request. 59 | - (void)recordMechanism:(NSString *)mechanism forRequestID:(NSString *)requestID; 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZNetworkTransaction.h: -------------------------------------------------------------------------------- 1 | // 2 | // VZNetworkObserver.h 3 | // Derived from: 4 | // 5 | // VZNetworkTransaction 6 | // Flipboard 7 | // 8 | // Created by Ryan Olson on 2/8/15. 9 | // Copyright (c) 2015 Flipboard. All rights reserved. 10 | // 11 | 12 | #import 13 | 14 | typedef NS_ENUM(NSInteger, VZNetworkTransactionState) { 15 | VZNetworkTransactionStateUnstarted, 16 | VZNetworkTransactionStateAwaitingResponse, 17 | VZNetworkTransactionStateReceivingData, 18 | VZNetworkTransactionStateFinished, 19 | VZNetworkTransactionStateFailed 20 | }; 21 | 22 | @interface VZNetworkTransaction : NSObject 23 | 24 | @property (nonatomic, copy) NSString *requestID; 25 | 26 | @property (nonatomic, strong) NSURLRequest *request; 27 | @property (nonatomic, strong) NSURLResponse *response; 28 | @property (nonatomic, copy) NSString *requestMechanism; 29 | @property (nonatomic, assign) VZNetworkTransactionState transactionState; 30 | @property (nonatomic, strong) NSError *error; 31 | 32 | @property (nonatomic, strong) NSDate *startTime; 33 | @property (nonatomic, assign) NSTimeInterval latency; 34 | @property (nonatomic, assign) NSTimeInterval duration; 35 | @property (nonatomic, assign) int64_t gzipDataLength; 36 | @property (nonatomic, assign) int64_t receivedDataLength; 37 | 38 | @property (nonatomic, strong, readonly) NSData *postBodyData; 39 | 40 | /// Only applicable for image downloads. A small thumbnail to preview the full response. 41 | //@property (nonatomic, strong) UIImage *responseThumbnail; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /VZInspector/toolbox/network/VZNetworkTransaction.m: -------------------------------------------------------------------------------- 1 | // 2 | // VZNetworkObserver.m 3 | // Derived from: 4 | // 5 | // VZNetworkTransaction 6 | // Flipboard 7 | // 8 | // Created by Ryan Olson on 2/8/15. 9 | // Copyright (c) 2015 Flipboard. All rights reserved. 10 | 11 | #import "VZNetworkTransaction.h" 12 | #import "VZInspectorUtility.h" 13 | 14 | @implementation VZNetworkTransaction 15 | 16 | @synthesize postBodyData = _postBodyData; 17 | 18 | - (NSString *)description 19 | { 20 | NSString *description = [super description]; 21 | 22 | description = [description stringByAppendingFormat:@" id = %@;", self.requestID]; 23 | description = [description stringByAppendingFormat:@" url = %@;", self.request.URL]; 24 | description = [description stringByAppendingFormat:@" duration = %f;", self.duration]; 25 | description = [description stringByAppendingFormat:@" receivedDataLength = %lld", self.receivedDataLength]; 26 | 27 | NSString* stateStr = @""; 28 | switch (self.transactionState) { 29 | case VZNetworkTransactionStateUnstarted: 30 | stateStr = @"state = Unstarted"; 31 | break; 32 | 33 | case VZNetworkTransactionStateAwaitingResponse: 34 | stateStr = @"state = Awaiting Response"; 35 | break; 36 | 37 | case VZNetworkTransactionStateReceivingData: 38 | stateStr = @"state = Receiving Data"; 39 | break; 40 | 41 | case VZNetworkTransactionStateFinished: 42 | stateStr = @"state = Finished"; 43 | break; 44 | 45 | case VZNetworkTransactionStateFailed: 46 | stateStr = @"state = Failed"; 47 | break; 48 | } 49 | 50 | return [description stringByAppendingString:stateStr]; 51 | } 52 | 53 | - (NSData *)postBodyData 54 | { 55 | if (!_postBodyData) { 56 | NSData *bodyData = self.request.HTTPBody; 57 | if ([bodyData length] > 0) { 58 | NSString *contentEncoding = [self.request valueForHTTPHeaderField:@"Content-Encoding"]; 59 | if ([contentEncoding rangeOfString:@"deflate" options:NSCaseInsensitiveSearch].length > 0 || [contentEncoding rangeOfString:@"gzip" options:NSCaseInsensitiveSearch].length > 0) { 60 | bodyData = [VZInspectorUtility inflatedDataFromCompressedData:bodyData]; 61 | } 62 | } 63 | _postBodyData = bodyData; 64 | } 65 | return _postBodyData; 66 | } 67 | 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /VZInspector/toolbox/sandbox/VZInspectorSandBoxRootView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "VZInspectorView.h" 6 | 7 | @interface VZInspectorSandBoxRootView : VZInspectorView 8 | 9 | 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /VZInspector/toolbox/sandbox/VZInspectorSandBoxRootView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #include 6 | #import "VZInspectorSandBoxRootView.h" 7 | #import "VZInspectorSandBoxSubView.h" 8 | 9 | 10 | @interface VZInspectorSandBoxHeaderView : UIView 11 | 12 | @property(nonatomic,strong) UILabel* textLabel; 13 | @property(nonatomic,strong) UIButton* backBtn; 14 | @property(nonatomic,weak) id delegate; 15 | 16 | @end 17 | 18 | @implementation VZInspectorSandBoxHeaderView 19 | 20 | - (id)initWithFrame:(CGRect)frame 21 | { 22 | self = [super initWithFrame:frame]; 23 | 24 | if (self) { 25 | 26 | self.textLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 13, frame.size.width, 18)]; 27 | self.textLabel.textAlignment = NSTextAlignmentCenter; 28 | self.textLabel.textColor = [UIColor whiteColor]; 29 | self.textLabel.backgroundColor = [UIColor clearColor]; 30 | self.textLabel.font = [UIFont systemFontOfSize:18.0f]; 31 | [self addSubview:self.textLabel]; 32 | 33 | self.backBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 0, 44, 44)]; 34 | self.backBtn.backgroundColor = [UIColor clearColor]; 35 | [self.backBtn setTitle:@"<-" forState:UIControlStateNormal]; 36 | [self.backBtn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; 37 | self.backBtn.titleLabel.font = [UIFont systemFontOfSize:18.0f]; 38 | #pragma clang diagnostic push 39 | #pragma clang diagnostic ignored "-Wundeclared-selector" 40 | [self.backBtn addTarget:self.delegate action:@selector(pop) forControlEvents:UIControlEventTouchUpInside]; 41 | #pragma clang diagnostic pop 42 | [self addSubview:self.backBtn]; 43 | } 44 | return self; 45 | } 46 | 47 | @end 48 | 49 | @interface VZInspectorSandBoxRootView() 50 | 51 | @property(nonatomic,strong)NSMutableArray* stack; 52 | @property(nonatomic,strong)VZInspectorSandBoxHeaderView* headerView; 53 | @property(nonatomic,strong)NSString* homepath; 54 | @property(nonatomic,strong)NSString* filepath; 55 | @property(nonatomic,strong)NSString* filename; 56 | @property(nonatomic,strong)VZInspectorSandBoxSubView* currentView; 57 | 58 | @end 59 | 60 | @implementation VZInspectorSandBoxRootView 61 | 62 | - (id)initWithFrame:(CGRect)frame 63 | { 64 | self = [super initWithFrame:frame]; 65 | 66 | if (self) { 67 | 68 | self.stack = [NSMutableArray new]; 69 | self.homepath = NSHomeDirectory(); 70 | 71 | self.headerView = [[VZInspectorSandBoxHeaderView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, 44)]; 72 | self.headerView.delegate = self; 73 | [self addSubview:self.headerView]; 74 | 75 | [self loadRootView]; 76 | 77 | } 78 | return self; 79 | } 80 | 81 | - (void)loadRootView 82 | { 83 | VZInspectorSandBoxSubView* rootView = [[VZInspectorSandBoxSubView alloc]initWithFrame:CGRectMake(0, 44, self.frame.size.width, self.frame.size.height-44) dir:self.homepath appendBundle:YES]; 84 | rootView.layer.borderColor = [UIColor colorWithWhite:0.5f alpha:1.0f].CGColor; 85 | rootView.layer.borderWidth = 2.0f; 86 | rootView.delegate = self; 87 | 88 | 89 | [self.stack addObject:rootView]; 90 | [self addSubview:rootView]; 91 | self.currentView = rootView; 92 | self.filename = @"Root"; 93 | self.filepath = self.homepath; 94 | self.headerView.textLabel.text = self.filename; 95 | 96 | } 97 | 98 | - (void)push 99 | { 100 | VZInspectorSandBoxSubView* targetView = [[VZInspectorSandBoxSubView alloc]initWithFrame:CGRectMake(self.frame.size.width, 44, self.frame.size.width, self.frame.size.height-44) dir:self.filepath appendBundle:NO]; 101 | targetView.delegate = self; 102 | targetView.alpha = 0.0f; 103 | [self addSubview:targetView]; 104 | 105 | 106 | VZInspectorSandBoxSubView* currentView = self.currentView; 107 | 108 | [UIView animateWithDuration:0.4 animations:^{ 109 | 110 | currentView.alpha = 0.0f; 111 | currentView.frame = CGRectMake(-CGRectGetWidth(currentView.bounds), 44, CGRectGetWidth(currentView.bounds), CGRectGetHeight(currentView.bounds)); 112 | 113 | targetView.frame = CGRectMake(0, 44, CGRectGetWidth(targetView.bounds), CGRectGetHeight(targetView.bounds)); 114 | targetView.alpha = 1.0f; 115 | 116 | } completion:^(BOOL finished) { 117 | 118 | [self.stack addObject:targetView]; 119 | currentView.frame = CGRectMake(0, 0, CGRectGetWidth(currentView.bounds), CGRectGetHeight(currentView.bounds)); 120 | self.currentView = targetView; 121 | }]; 122 | 123 | } 124 | 125 | - (void)pop 126 | { 127 | if (self.stack.count <2) { 128 | 129 | #pragma clang diagnostic push 130 | #pragma clang diagnostic ignored "-Wundeclared-selector" 131 | [self.parentViewController performSelector:@selector(onBack)]; 132 | #pragma clang diagnostic pop 133 | 134 | } 135 | else 136 | { 137 | VZInspectorSandBoxSubView* currentView = self.currentView; 138 | currentView.alpha = 1.0f; 139 | 140 | VZInspectorSandBoxSubView* belowView = self.stack[self.stack.count - 2]; 141 | belowView.alpha = 0.0f; 142 | 143 | belowView.frame = CGRectMake(-CGRectGetWidth(belowView.bounds), 44, CGRectGetWidth(belowView.bounds), CGRectGetHeight(belowView.bounds)); 144 | [UIView animateWithDuration:0.4 animations:^{ 145 | 146 | currentView.frame = CGRectMake(self.frame.size.width, 44, CGRectGetWidth(currentView.bounds), CGRectGetHeight(currentView.bounds)); 147 | currentView.alpha = 0.0f; 148 | 149 | belowView.frame = CGRectMake(0, 44,CGRectGetWidth(belowView.bounds), CGRectGetHeight(belowView.bounds)); 150 | belowView.alpha = 1.0f; 151 | 152 | } completion:^(BOOL finished) { 153 | 154 | 155 | [self.stack removeObject:currentView]; 156 | [currentView removeFromSuperview]; 157 | self.currentView = belowView; 158 | //self.headerView.textLabel.text = self.currentView.currentDir; 159 | 160 | 161 | }]; 162 | } 163 | } 164 | 165 | - (void)onSubViewDidSelect:(NSInteger)index FileName:(NSString *)file 166 | { 167 | self.filepath = file; 168 | [self push]; 169 | 170 | } 171 | 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /VZInspector/toolbox/sandbox/VZInspectorSandBoxSubView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface VZInspectorSandBoxItem : NSObject 8 | 9 | @property(nonatomic,strong) NSString* name; 10 | @property(nonatomic,strong) NSString* path; 11 | 12 | @end 13 | 14 | 15 | @protocol VZInspectorSandBoxSubViewCallBackProtocol 16 | 17 | @optional 18 | - (void)onSubViewDidSelect:(NSInteger)index FileName:(NSString* )file; 19 | @end 20 | 21 | @interface VZInspectorSandBoxSubView : UIView 22 | 23 | @property(nonatomic,weak) id delegate; 24 | @property(nonatomic,strong)NSString* currentDir; 25 | 26 | - (id)initWithFrame:(CGRect)frame dir:(NSString* )dir appendBundle:(BOOL)appendBundle; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /VZInspectorDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /VZInspectorDemo.xcodeproj/xcshareddata/xcschemes/VZInspectorDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /VZInspectorDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface AppDelegate : UIResponder 8 | 9 | @property (strong, nonatomic) UIWindow *window; 10 | 11 | 12 | @end 13 | 14 | -------------------------------------------------------------------------------- /VZInspectorDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import "AppDelegate.h" 6 | #import "VZInspector.h" 7 | 8 | @interface AppDelegate () 9 | 10 | @end 11 | 12 | @implementation AppDelegate 13 | 14 | 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 17 | 18 | [VZInspector setClassPrefixName:@"VZ"]; 19 | [VZInspector setShouldHandleCrash:true]; 20 | [VZInspector setShouldHookNetworkRequest:true]; 21 | [VZInspector setLogNumbers:10]; 22 | [VZInspector addObserveCallback:^NSString *{ 23 | 24 | NSString* v = [NSString stringWithFormat:@"System Ver:%@\n",[UIDevice currentDevice].systemVersion]; 25 | NSString* n = [NSString stringWithFormat:@"System Name:%@\n",[UIDevice currentDevice].systemName]; 26 | NSString* ret = [v stringByAppendingString:n]; 27 | return ret; 28 | }]; 29 | 30 | //add custom plugin 31 | [self addCustomPlugin]; 32 | [VZInspector showOnStatusBar]; 33 | 34 | return YES; 35 | } 36 | 37 | - (void)addCustomPlugin{ 38 | 39 | #if TARGET_OS_SIMULATOR 40 | u_int8_t bytesIcon[] = {0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x3c,0x8,0x3,0x0,0x0,0x0,0xd,0x22,0x29,0x40,0x0,0x0,0x0,0x42,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0xff,0x80,0x20,0xfd,0x80,0x22,0xff,0x82,0x20,0xfc,0x80,0x23,0xfd,0x81,0x22,0xff,0x80,0x20,0xfd,0x80,0x22,0xfc,0x80,0x23,0xfc,0x80,0x23,0xff,0x80,0x20,0xfd,0x80,0x22,0xfd,0x80,0x22,0xfd,0x80,0x23,0xfd,0x80,0x22,0xfd,0x80,0x22,0xfd,0x7f,0x22,0xfd,0x80,0x22,0xff,0x80,0x20,0xfd,0x80,0x22,0xfd,0x80,0x22,0xfd,0x80,0x23,0xcd,0xd0,0x2,0x56,0x0,0x0,0x0,0x15,0x74,0x52,0x4e,0x53,0x0,0x40,0x80,0x3f,0xc0,0x7f,0x30,0xef,0x60,0xbf,0x20,0xe0,0x9f,0xa0,0xdf,0xd0,0x90,0xcf,0x10,0x70,0xf0,0x42,0x95,0x4e,0x90,0x0,0x0,0x0,0xba,0x49,0x44,0x41,0x54,0x78,0x5e,0xed,0xd5,0xcb,0xe,0x84,0x20,0xc,0x86,0x51,0xa8,0x1d,0x1c,0xf0,0x32,0x57,0xdf,0xff,0x55,0xc7,0x5,0x9,0xf9,0x49,0x98,0xd2,0x5d,0x35,0x7e,0x1b,0x6c,0xcc,0x59,0x11,0xc0,0x1d,0xbb,0x34,0x48,0xa5,0x36,0xa6,0x4d,0x6a,0xc,0x2,0x56,0x68,0xc4,0x6a,0x8d,0x78,0xa1,0x56,0xcf,0xa2,0x5b,0xd8,0xbb,0x66,0x77,0xd4,0x32,0x96,0x35,0x62,0xa5,0x46,0xac,0xd4,0x88,0x95,0x1a,0xb1,0x52,0x23,0x56,0x6b,0xc4,0x5b,0xe,0x47,0x42,0x4d,0x4a,0xc,0x5a,0x8f,0xb3,0x16,0xf0,0x97,0x99,0xa7,0x8c,0x99,0xf9,0x1,0xd8,0x7d,0xfe,0x63,0xc6,0x9d,0xf3,0x88,0xbd,0x1d,0x7c,0xe1,0x31,0xc6,0xb8,0x66,0xbc,0x7f,0xbe,0x76,0xbc,0xee,0x6b,0xe8,0xc0,0xa5,0x7a,0xb4,0x8b,0x85,0xec,0xe2,0xea,0x49,0x1c,0x4a,0x6f,0x11,0xe3,0xe9,0xc7,0xad,0xb2,0x8c,0x89,0x68,0x41,0x3c,0x11,0x11,0xcb,0xb8,0xfe,0xd,0xe7,0xc4,0x0,0xbe,0xf0,0x19,0x6e,0x12,0x2e,0x85,0x6a,0x3c,0xe5,0x35,0x34,0xdf,0x3a,0x9a,0x1b,0xb8,0x2f,0x53,0x38,0x79,0x45,0xc9,0x1d,0xba,0x1f,0x58,0xfe,0x52,0xb5,0x1a,0x3,0x1e,0x7e,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82}; 41 | 42 | UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy:bytesIcon length:sizeof(bytesIcon) freeWhenDone:NO]]; 43 | 44 | [VZInspector addToolItem:[VZInspectorToolItem itemWithName:@"File Bytes" icon:image callback:^{ 45 | NSString *file = [UIPasteboard generalPasteboard].string; 46 | NSData *data; 47 | NSString *message; 48 | if ([file hasPrefix:@"/"]) { 49 | data = [NSData dataWithContentsOfFile:file]; 50 | if (data) { 51 | NSUInteger len = [data length]; 52 | Byte *bytes = (Byte *)[data bytes]; 53 | NSMutableString *str = @"{".mutableCopy; 54 | for (int i=0; i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /VZInspectorDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /VZInspectorDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /VZInspectorDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | @interface ViewController : UIViewController 8 | 9 | 10 | @end 11 | 12 | -------------------------------------------------------------------------------- /VZInspectorDemo/ViewController.mm: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // VZInspectorDemo 4 | // 5 | // Created by moxin on 9/11/18. 6 | // Copyright © 2018 Tao Xu. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #include 11 | 12 | @interface ViewController() 13 | @property(nonatomic,strong) id list; 14 | @property(nonatomic,strong) UITableView* tableView; 15 | @property(nonatomic,strong) NSMutableArray* items; 16 | 17 | @end 18 | 19 | @implementation ViewController 20 | 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | [self setTitle:@"Inspector Demo"]; 26 | self.edgesForExtendedLayout = UIRectEdgeNone; 27 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(load)]; 28 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(memoryPeek)]; 29 | 30 | self.items = [NSMutableArray new]; 31 | 32 | self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds)-64)]; 33 | self.tableView.delegate = self; 34 | self.tableView.dataSource = self; 35 | [self.view addSubview:self.tableView]; 36 | [self load]; 37 | 38 | 39 | } 40 | 41 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 42 | { 43 | return 1; 44 | } 45 | 46 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 47 | { 48 | return self.items.count; 49 | } 50 | 51 | - (UITableViewCell* )tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 52 | { 53 | static NSString* identifier = @"vzinspectordemo"; 54 | UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 55 | 56 | if (!cell) { 57 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; 58 | } 59 | 60 | NSDictionary* info = self.items[indexPath.row]; 61 | cell.textLabel.font = [UIFont boldSystemFontOfSize:18.0f]; 62 | cell.textLabel.numberOfLines = 0; 63 | cell.textLabel.text = info[@"title"]; 64 | [cell.textLabel sizeToFit]; 65 | 66 | cell.detailTextLabel.text = info[@"body"]; 67 | cell.detailTextLabel.font = [UIFont systemFontOfSize:12.0f]; 68 | cell.detailTextLabel.numberOfLines = 0; 69 | [cell.detailTextLabel sizeToFit]; 70 | 71 | return cell; 72 | 73 | } 74 | 75 | - (void)load 76 | { 77 | [self.items removeAllObjects]; 78 | [self.tableView reloadData]; 79 | self.tableView.tableFooterView = [self loadingFooterView]; 80 | 81 | NSString* url = @"https://jsonplaceholder.typicode.com/posts/"; 82 | [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 83 | 84 | if(data){ 85 | 86 | NSDictionary* JSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 87 | 88 | NSLog(@"%@",JSON); 89 | 90 | for (NSDictionary* dict in JSON) { 91 | [self.items addObject:dict]; 92 | } 93 | dispatch_async(dispatch_get_main_queue(), ^{ 94 | 95 | self.tableView.tableFooterView = nil; 96 | [self.tableView reloadData]; 97 | 98 | }); 99 | } 100 | else{ 101 | dispatch_async(dispatch_get_main_queue(), ^{ 102 | 103 | [self alert:@"Error"]; 104 | self.tableView.tableFooterView = nil; 105 | }); 106 | } 107 | 108 | 109 | }] resume]; 110 | 111 | } 112 | 113 | - (void)memoryPeek 114 | { 115 | static int* _ptr = nullptr; 116 | static std::allocator _allocator; 117 | // static std::allocator::size_type sz = 1024*1024*1024*sizeof(int); //this will trigger memory warning 118 | static std::allocator::size_type sz = 1024*1024*sizeof(int); 119 | 120 | if(_ptr){ 121 | _allocator.deallocate(_ptr, sz); 122 | _ptr = nullptr; 123 | [self alert:@"Clear"]; 124 | }else{ 125 | _ptr = _allocator.allocate(sz); 126 | _allocator.construct(_ptr, 0); 127 | NSString* msg = [NSString stringWithFormat:@"Alloc %ld MB memory",sizeof(int)]; 128 | [self alert:msg]; 129 | } 130 | } 131 | #pragma mark - private method 132 | 133 | - (void)alert:(NSString*) title{ 134 | UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; 135 | [alert show]; 136 | } 137 | 138 | 139 | - (UIView* )loadingFooterView 140 | { 141 | UIView* v = [[UIView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 44)]; 142 | UIActivityIndicatorView* indicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake((CGRectGetWidth(self.view.bounds)-20)/2, 11, 20, 20)]; 143 | indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; 144 | [indicator startAnimating]; 145 | [v addSubview:indicator]; 146 | 147 | return v; 148 | } 149 | 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /VZInspectorDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016年 Vizlab. All rights reserved. 3 | // 4 | 5 | #import 6 | #import "AppDelegate.h" 7 | 8 | int main(int argc, char * argv[]) { 9 | @autoreleasepool { 10 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xta0/VZInspector/506e27b2a7be94651cb020981df50f071f458466/logo.png --------------------------------------------------------------------------------