├── .github └── FUNDING.yml ├── .gitignore ├── GDPerformanceView.podspec ├── GDPerformanceView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── daniilmbox.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── Daniil.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── FSPerfomanceView.xcscheme │ │ └── xcschememanagement.plist │ └── daniilmbox.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── GDPerformanceView.xcscheme │ └── xcschememanagement.plist ├── GDPerformanceView ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── GDPerformanceMonitoring │ ├── GDMarginLabel.h │ ├── GDMarginLabel.m │ ├── GDPerformanceMonitor.h │ ├── GDPerformanceMonitor.m │ ├── GDPerformanceMonitorProtocol.h │ ├── GDPerformanceView.h │ ├── GDPerformanceView.m │ ├── GDWindowViewController.h │ └── GDWindowViewController.m ├── Info.plist └── main.m ├── LICENSE ├── README.md ├── performance_view.PNG ├── performance_view_2.PNG ├── performance_view_3.PNG └── performance_view_4.PNG /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: ['dani-gavrilov'] 4 | # patreon: # Replace with a single Patreon username 5 | # open_collective: # Replace with a single Open Collective username 6 | # ko_fi: # Replace with a single Ko-fi username 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: # Replace with a single Liberapay username 10 | # issuehunt: # Replace with a single IssueHunt username 11 | # otechie: # Replace with a single Otechie username 12 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | DerivedData 5 | .idea/ -------------------------------------------------------------------------------- /GDPerformanceView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "GDPerformanceView" 3 | s.version = "1.3.1" 4 | s.summary = "Shows FPS, CPU usage, app and iOS versions above the status bar and report FPS and CPU usage via delegate." 5 | s.homepage = "https://github.com/dani-gavrilov/GDPerformanceView" 6 | s.license = { :type => "MIT", :file => "LICENSE" } 7 | s.author = { "Gavrilov Daniil" => "daniilmbox@gmail.com" } 8 | s.platform = :ios, "8.0" 9 | s.ios.deployment_target = "8.0" 10 | s.source = { :git => "https://github.com/dani-gavrilov/GDPerformanceView.git", :tag => "1.3.1" } 11 | s.source_files = "GDPerformanceView/GDPerformanceMonitoring/*" 12 | s.frameworks = "UIKit", "Foundation", "QuartzCore" 13 | s.requires_arc = true 14 | end 15 | -------------------------------------------------------------------------------- /GDPerformanceView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4277368A1E2BD55100E59793 /* GDWindowViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 427736891E2BD55100E59793 /* GDWindowViewController.m */; }; 11 | A537615E1DB76D81000007B7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A53761511DB76D81000007B7 /* AppDelegate.m */; }; 12 | A537615F1DB76D81000007B7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A53761521DB76D81000007B7 /* Assets.xcassets */; }; 13 | A53761601DB76D81000007B7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A53761531DB76D81000007B7 /* LaunchScreen.storyboard */; }; 14 | A53761611DB76D81000007B7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A53761551DB76D81000007B7 /* Main.storyboard */; }; 15 | A53761621DB76D81000007B7 /* GDPerformanceMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = A53761591DB76D81000007B7 /* GDPerformanceMonitor.m */; }; 16 | A53761631DB76D81000007B7 /* GDPerformanceView.m in Sources */ = {isa = PBXBuildFile; fileRef = A537615B1DB76D81000007B7 /* GDPerformanceView.m */; }; 17 | A53761651DB76D81000007B7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A537615D1DB76D81000007B7 /* main.m */; }; 18 | A5DAC0811DB7B1A600AF26E6 /* GDMarginLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = A5DAC0801DB7B1A600AF26E6 /* GDMarginLabel.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 427736881E2BD55100E59793 /* GDWindowViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDWindowViewController.h; sourceTree = ""; }; 23 | 427736891E2BD55100E59793 /* GDWindowViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GDWindowViewController.m; sourceTree = ""; }; 24 | 428FE57D1E1D19D100F85C8B /* GDPerformanceMonitorProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDPerformanceMonitorProtocol.h; sourceTree = ""; }; 25 | A53761501DB76D81000007B7 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 26 | A53761511DB76D81000007B7 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 27 | A53761521DB76D81000007B7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 28 | A53761541DB76D81000007B7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 29 | A53761561DB76D81000007B7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 30 | A53761581DB76D81000007B7 /* GDPerformanceMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDPerformanceMonitor.h; sourceTree = ""; }; 31 | A53761591DB76D81000007B7 /* GDPerformanceMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GDPerformanceMonitor.m; sourceTree = ""; }; 32 | A537615A1DB76D81000007B7 /* GDPerformanceView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDPerformanceView.h; sourceTree = ""; }; 33 | A537615B1DB76D81000007B7 /* GDPerformanceView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GDPerformanceView.m; sourceTree = ""; }; 34 | A537615C1DB76D81000007B7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | A537615D1DB76D81000007B7 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 36 | A5C8CEBE1DB6203D008D8E15 /* GDPerformanceView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GDPerformanceView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | A5DAC07F1DB7B1A600AF26E6 /* GDMarginLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDMarginLabel.h; sourceTree = ""; }; 38 | A5DAC0801DB7B1A600AF26E6 /* GDMarginLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GDMarginLabel.m; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | A5C8CEBB1DB6203D008D8E15 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | A537614F1DB76D81000007B7 /* GDPerformanceView */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | A53761571DB76D81000007B7 /* GDPerformanceMonitoring */, 56 | A53761501DB76D81000007B7 /* AppDelegate.h */, 57 | A53761511DB76D81000007B7 /* AppDelegate.m */, 58 | A53761521DB76D81000007B7 /* Assets.xcassets */, 59 | A53761531DB76D81000007B7 /* LaunchScreen.storyboard */, 60 | A53761551DB76D81000007B7 /* Main.storyboard */, 61 | A537615C1DB76D81000007B7 /* Info.plist */, 62 | A537615D1DB76D81000007B7 /* main.m */, 63 | ); 64 | path = GDPerformanceView; 65 | sourceTree = ""; 66 | }; 67 | A53761571DB76D81000007B7 /* GDPerformanceMonitoring */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | A53761581DB76D81000007B7 /* GDPerformanceMonitor.h */, 71 | A53761591DB76D81000007B7 /* GDPerformanceMonitor.m */, 72 | A537615A1DB76D81000007B7 /* GDPerformanceView.h */, 73 | A537615B1DB76D81000007B7 /* GDPerformanceView.m */, 74 | A5DAC07F1DB7B1A600AF26E6 /* GDMarginLabel.h */, 75 | A5DAC0801DB7B1A600AF26E6 /* GDMarginLabel.m */, 76 | 427736881E2BD55100E59793 /* GDWindowViewController.h */, 77 | 427736891E2BD55100E59793 /* GDWindowViewController.m */, 78 | 428FE57D1E1D19D100F85C8B /* GDPerformanceMonitorProtocol.h */, 79 | ); 80 | path = GDPerformanceMonitoring; 81 | sourceTree = ""; 82 | }; 83 | A5C8CEB51DB6203D008D8E15 = { 84 | isa = PBXGroup; 85 | children = ( 86 | A537614F1DB76D81000007B7 /* GDPerformanceView */, 87 | A5C8CEBF1DB6203D008D8E15 /* Products */, 88 | ); 89 | sourceTree = ""; 90 | }; 91 | A5C8CEBF1DB6203D008D8E15 /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | A5C8CEBE1DB6203D008D8E15 /* GDPerformanceView.app */, 95 | ); 96 | name = Products; 97 | sourceTree = ""; 98 | }; 99 | /* End PBXGroup section */ 100 | 101 | /* Begin PBXNativeTarget section */ 102 | A5C8CEBD1DB6203D008D8E15 /* GDPerformanceView */ = { 103 | isa = PBXNativeTarget; 104 | buildConfigurationList = A5C8CED51DB6203D008D8E15 /* Build configuration list for PBXNativeTarget "GDPerformanceView" */; 105 | buildPhases = ( 106 | A5C8CEBA1DB6203D008D8E15 /* Sources */, 107 | A5C8CEBB1DB6203D008D8E15 /* Frameworks */, 108 | A5C8CEBC1DB6203D008D8E15 /* Resources */, 109 | ); 110 | buildRules = ( 111 | ); 112 | dependencies = ( 113 | ); 114 | name = GDPerformanceView; 115 | productName = FSPerfomanceView; 116 | productReference = A5C8CEBE1DB6203D008D8E15 /* GDPerformanceView.app */; 117 | productType = "com.apple.product-type.application"; 118 | }; 119 | /* End PBXNativeTarget section */ 120 | 121 | /* Begin PBXProject section */ 122 | A5C8CEB61DB6203D008D8E15 /* Project object */ = { 123 | isa = PBXProject; 124 | attributes = { 125 | CLASSPREFIX = GD; 126 | LastUpgradeCheck = 0820; 127 | ORGANIZATIONNAME = "Gavrilov Daniil"; 128 | TargetAttributes = { 129 | A5C8CEBD1DB6203D008D8E15 = { 130 | CreatedOnToolsVersion = 8.0; 131 | ProvisioningStyle = Automatic; 132 | }; 133 | }; 134 | }; 135 | buildConfigurationList = A5C8CEB91DB6203D008D8E15 /* Build configuration list for PBXProject "GDPerformanceView" */; 136 | compatibilityVersion = "Xcode 3.2"; 137 | developmentRegion = English; 138 | hasScannedForEncodings = 0; 139 | knownRegions = ( 140 | en, 141 | Base, 142 | ); 143 | mainGroup = A5C8CEB51DB6203D008D8E15; 144 | productRefGroup = A5C8CEBF1DB6203D008D8E15 /* Products */; 145 | projectDirPath = ""; 146 | projectRoot = ""; 147 | targets = ( 148 | A5C8CEBD1DB6203D008D8E15 /* GDPerformanceView */, 149 | ); 150 | }; 151 | /* End PBXProject section */ 152 | 153 | /* Begin PBXResourcesBuildPhase section */ 154 | A5C8CEBC1DB6203D008D8E15 /* Resources */ = { 155 | isa = PBXResourcesBuildPhase; 156 | buildActionMask = 2147483647; 157 | files = ( 158 | A53761611DB76D81000007B7 /* Main.storyboard in Resources */, 159 | A537615F1DB76D81000007B7 /* Assets.xcassets in Resources */, 160 | A53761601DB76D81000007B7 /* LaunchScreen.storyboard in Resources */, 161 | ); 162 | runOnlyForDeploymentPostprocessing = 0; 163 | }; 164 | /* End PBXResourcesBuildPhase section */ 165 | 166 | /* Begin PBXSourcesBuildPhase section */ 167 | A5C8CEBA1DB6203D008D8E15 /* Sources */ = { 168 | isa = PBXSourcesBuildPhase; 169 | buildActionMask = 2147483647; 170 | files = ( 171 | A53761621DB76D81000007B7 /* GDPerformanceMonitor.m in Sources */, 172 | 4277368A1E2BD55100E59793 /* GDWindowViewController.m in Sources */, 173 | A537615E1DB76D81000007B7 /* AppDelegate.m in Sources */, 174 | A53761651DB76D81000007B7 /* main.m in Sources */, 175 | A53761631DB76D81000007B7 /* GDPerformanceView.m in Sources */, 176 | A5DAC0811DB7B1A600AF26E6 /* GDMarginLabel.m in Sources */, 177 | ); 178 | runOnlyForDeploymentPostprocessing = 0; 179 | }; 180 | /* End PBXSourcesBuildPhase section */ 181 | 182 | /* Begin PBXVariantGroup section */ 183 | A53761531DB76D81000007B7 /* LaunchScreen.storyboard */ = { 184 | isa = PBXVariantGroup; 185 | children = ( 186 | A53761541DB76D81000007B7 /* Base */, 187 | ); 188 | name = LaunchScreen.storyboard; 189 | sourceTree = ""; 190 | }; 191 | A53761551DB76D81000007B7 /* Main.storyboard */ = { 192 | isa = PBXVariantGroup; 193 | children = ( 194 | A53761561DB76D81000007B7 /* Base */, 195 | ); 196 | name = Main.storyboard; 197 | sourceTree = ""; 198 | }; 199 | /* End PBXVariantGroup section */ 200 | 201 | /* Begin XCBuildConfiguration section */ 202 | A5C8CED31DB6203D008D8E15 /* Debug */ = { 203 | isa = XCBuildConfiguration; 204 | buildSettings = { 205 | ALWAYS_SEARCH_USER_PATHS = NO; 206 | CLANG_ANALYZER_NONNULL = YES; 207 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 208 | CLANG_CXX_LIBRARY = "libc++"; 209 | CLANG_ENABLE_MODULES = YES; 210 | CLANG_ENABLE_OBJC_ARC = YES; 211 | CLANG_WARN_BOOL_CONVERSION = YES; 212 | CLANG_WARN_CONSTANT_CONVERSION = YES; 213 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 214 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 215 | CLANG_WARN_EMPTY_BODY = YES; 216 | CLANG_WARN_ENUM_CONVERSION = YES; 217 | CLANG_WARN_INFINITE_RECURSION = YES; 218 | CLANG_WARN_INT_CONVERSION = YES; 219 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 220 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 221 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 222 | CLANG_WARN_UNREACHABLE_CODE = YES; 223 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 224 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 225 | COPY_PHASE_STRIP = NO; 226 | DEBUG_INFORMATION_FORMAT = dwarf; 227 | ENABLE_STRICT_OBJC_MSGSEND = YES; 228 | ENABLE_TESTABILITY = YES; 229 | GCC_C_LANGUAGE_STANDARD = gnu99; 230 | GCC_DYNAMIC_NO_PIC = NO; 231 | GCC_NO_COMMON_BLOCKS = YES; 232 | GCC_OPTIMIZATION_LEVEL = 0; 233 | GCC_PREPROCESSOR_DEFINITIONS = ( 234 | "DEBUG=1", 235 | "$(inherited)", 236 | ); 237 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 238 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 239 | GCC_WARN_UNDECLARED_SELECTOR = YES; 240 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 241 | GCC_WARN_UNUSED_FUNCTION = YES; 242 | GCC_WARN_UNUSED_VARIABLE = YES; 243 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 244 | MTL_ENABLE_DEBUG_INFO = YES; 245 | ONLY_ACTIVE_ARCH = YES; 246 | SDKROOT = iphoneos; 247 | TARGETED_DEVICE_FAMILY = "1,2"; 248 | }; 249 | name = Debug; 250 | }; 251 | A5C8CED41DB6203D008D8E15 /* Release */ = { 252 | isa = XCBuildConfiguration; 253 | buildSettings = { 254 | ALWAYS_SEARCH_USER_PATHS = NO; 255 | CLANG_ANALYZER_NONNULL = YES; 256 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 257 | CLANG_CXX_LIBRARY = "libc++"; 258 | CLANG_ENABLE_MODULES = YES; 259 | CLANG_ENABLE_OBJC_ARC = YES; 260 | CLANG_WARN_BOOL_CONVERSION = YES; 261 | CLANG_WARN_CONSTANT_CONVERSION = YES; 262 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 263 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 264 | CLANG_WARN_EMPTY_BODY = YES; 265 | CLANG_WARN_ENUM_CONVERSION = YES; 266 | CLANG_WARN_INFINITE_RECURSION = YES; 267 | CLANG_WARN_INT_CONVERSION = YES; 268 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 269 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 270 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 271 | CLANG_WARN_UNREACHABLE_CODE = YES; 272 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 273 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 274 | COPY_PHASE_STRIP = NO; 275 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 276 | ENABLE_NS_ASSERTIONS = NO; 277 | ENABLE_STRICT_OBJC_MSGSEND = YES; 278 | GCC_C_LANGUAGE_STANDARD = gnu99; 279 | GCC_NO_COMMON_BLOCKS = YES; 280 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 281 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 282 | GCC_WARN_UNDECLARED_SELECTOR = YES; 283 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 284 | GCC_WARN_UNUSED_FUNCTION = YES; 285 | GCC_WARN_UNUSED_VARIABLE = YES; 286 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 287 | MTL_ENABLE_DEBUG_INFO = NO; 288 | SDKROOT = iphoneos; 289 | TARGETED_DEVICE_FAMILY = "1,2"; 290 | VALIDATE_PRODUCT = YES; 291 | }; 292 | name = Release; 293 | }; 294 | A5C8CED61DB6203D008D8E15 /* Debug */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 298 | DEVELOPMENT_TEAM = ""; 299 | INFOPLIST_FILE = GDPerformanceView/Info.plist; 300 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 301 | PRODUCT_BUNDLE_IDENTIFIER = GD.GDPerformanceView; 302 | PRODUCT_NAME = "$(TARGET_NAME)"; 303 | TARGETED_DEVICE_FAMILY = "1,2"; 304 | }; 305 | name = Debug; 306 | }; 307 | A5C8CED71DB6203D008D8E15 /* Release */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 311 | DEVELOPMENT_TEAM = ""; 312 | INFOPLIST_FILE = GDPerformanceView/Info.plist; 313 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 314 | PRODUCT_BUNDLE_IDENTIFIER = GD.GDPerformanceView; 315 | PRODUCT_NAME = "$(TARGET_NAME)"; 316 | TARGETED_DEVICE_FAMILY = "1,2"; 317 | }; 318 | name = Release; 319 | }; 320 | /* End XCBuildConfiguration section */ 321 | 322 | /* Begin XCConfigurationList section */ 323 | A5C8CEB91DB6203D008D8E15 /* Build configuration list for PBXProject "GDPerformanceView" */ = { 324 | isa = XCConfigurationList; 325 | buildConfigurations = ( 326 | A5C8CED31DB6203D008D8E15 /* Debug */, 327 | A5C8CED41DB6203D008D8E15 /* Release */, 328 | ); 329 | defaultConfigurationIsVisible = 0; 330 | defaultConfigurationName = Release; 331 | }; 332 | A5C8CED51DB6203D008D8E15 /* Build configuration list for PBXNativeTarget "GDPerformanceView" */ = { 333 | isa = XCConfigurationList; 334 | buildConfigurations = ( 335 | A5C8CED61DB6203D008D8E15 /* Debug */, 336 | A5C8CED71DB6203D008D8E15 /* Release */, 337 | ); 338 | defaultConfigurationIsVisible = 0; 339 | defaultConfigurationName = Release; 340 | }; 341 | /* End XCConfigurationList section */ 342 | }; 343 | rootObject = A5C8CEB61DB6203D008D8E15 /* Project object */; 344 | } 345 | -------------------------------------------------------------------------------- /GDPerformanceView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GDPerformanceView.xcodeproj/project.xcworkspace/xcuserdata/daniilmbox.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dani-gavrilov/GDPerformanceView/0cd10a2bda63e371bd7edc9e74e497bce3336951/GDPerformanceView.xcodeproj/project.xcworkspace/xcuserdata/daniilmbox.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /GDPerformanceView.xcodeproj/xcuserdata/Daniil.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /GDPerformanceView.xcodeproj/xcuserdata/Daniil.xcuserdatad/xcschemes/FSPerfomanceView.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 | -------------------------------------------------------------------------------- /GDPerformanceView.xcodeproj/xcuserdata/Daniil.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FSPerfomanceView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | A5C8CEBD1DB6203D008D8E15 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /GDPerformanceView.xcodeproj/xcuserdata/daniilmbox.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /GDPerformanceView.xcodeproj/xcuserdata/daniilmbox.xcuserdatad/xcschemes/GDPerformanceView.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 | -------------------------------------------------------------------------------- /GDPerformanceView.xcodeproj/xcuserdata/daniilmbox.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GDPerformanceView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | A5C8CEBD1DB6203D008D8E15 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /GDPerformanceView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import 24 | 25 | @interface AppDelegate : UIResponder 26 | 27 | @property (strong, nonatomic) UIWindow *window; 28 | 29 | @end 30 | 31 | -------------------------------------------------------------------------------- /GDPerformanceView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import "AppDelegate.h" 24 | 25 | #import "GDPerformanceMonitor.h" 26 | 27 | @interface AppDelegate () 28 | 29 | @end 30 | 31 | @implementation AppDelegate 32 | 33 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 34 | // Override point for customization after application launch. 35 | 36 | #ifdef DEBUG 37 | [[GDPerformanceMonitor sharedInstance] startMonitoring]; 38 | [[GDPerformanceMonitor sharedInstance] configureWithConfiguration:^(UILabel *textLabel) { 39 | [textLabel setBackgroundColor:[UIColor blackColor]]; 40 | [textLabel setTextColor:[UIColor whiteColor]]; 41 | [textLabel.layer setBorderColor:[[UIColor blackColor] CGColor]]; 42 | }]; 43 | #endif 44 | 45 | return YES; 46 | } 47 | 48 | - (void)applicationWillResignActive:(UIApplication *)application { 49 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 50 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 51 | } 52 | 53 | - (void)applicationDidEnterBackground:(UIApplication *)application { 54 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 55 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 56 | } 57 | 58 | - (void)applicationWillEnterForeground:(UIApplication *)application { 59 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 60 | } 61 | 62 | - (void)applicationDidBecomeActive:(UIApplication *)application { 63 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 64 | } 65 | 66 | - (void)applicationWillTerminate:(UIApplication *)application { 67 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 68 | 69 | #ifdef DEBUG 70 | [[GDPerformanceMonitor sharedInstance] stopMonitoring]; 71 | #endif 72 | 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /GDPerformanceView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /GDPerformanceView/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /GDPerformanceView/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 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /GDPerformanceView/GDPerformanceMonitoring/GDMarginLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import 24 | 25 | @interface GDMarginLabel : UILabel 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /GDPerformanceView/GDPerformanceMonitoring/GDMarginLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import "GDMarginLabel.h" 24 | 25 | @interface GDMarginLabel () 26 | 27 | @property (nonatomic, assign) UIEdgeInsets edgeInsets; 28 | 29 | @end 30 | 31 | @implementation GDMarginLabel 32 | 33 | #pragma mark - 34 | #pragma mark - Init Methods & Superclass Overriders 35 | 36 | - (id)initWithFrame:(CGRect)frame { 37 | self = [super initWithFrame:frame]; 38 | if (self) { 39 | self.edgeInsets = UIEdgeInsetsMake(0.0f, 5.0f, 0.0f, 5.0f); 40 | } 41 | return self; 42 | } 43 | 44 | - (void)drawTextInRect:(CGRect)rect { 45 | [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.edgeInsets)]; 46 | } 47 | 48 | - (CGSize)intrinsicContentSize { 49 | CGSize size = [super intrinsicContentSize]; 50 | size.width += self.edgeInsets.left + self.edgeInsets.right; 51 | size.height += self.edgeInsets.top + self.edgeInsets.bottom; 52 | return size; 53 | } 54 | 55 | - (CGSize)sizeThatFits:(CGSize)size { 56 | CGSize sizeThatFits = [super sizeThatFits:size]; 57 | sizeThatFits.width += self.edgeInsets.left + self.edgeInsets.right; 58 | sizeThatFits.height += self.edgeInsets.top + self.edgeInsets.bottom; 59 | return sizeThatFits; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /GDPerformanceView/GDPerformanceMonitoring/GDPerformanceMonitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import 24 | 25 | #import "GDPerformanceMonitorProtocol.h" 26 | 27 | @class UILabel; 28 | 29 | @interface GDPerformanceMonitor : NSObject 30 | 31 | /** 32 | GDPerformanceMonitorDelegate delegate. 33 | */ 34 | @property (nonatomic, weak) id delegate; 35 | 36 | /** 37 | Change it to hide or show application version from monitoring view. Default is NO. 38 | */ 39 | @property (nonatomic, getter=isAppVersionHidden) BOOL appVersionHidden; 40 | 41 | /** 42 | Change it to hide or show device iOS version from monitoring view. Default is NO. 43 | */ 44 | @property (nonatomic, getter=isDeviceVersionHidden) BOOL deviceVersionHidden; 45 | 46 | 47 | /** 48 | Creates and returns instance of GDPerformanceMonitor, as singleton. 49 | */ 50 | + (instancetype)sharedInstance; 51 | 52 | /** 53 | Creates and returns instance of GDPerformanceMonitor. 54 | */ 55 | - (instancetype)init NS_DESIGNATED_INITIALIZER; 56 | 57 | /** 58 | Overrides prefersStatusBarHidden and preferredStatusBarStyle properties to return the desired status bar attributes. 59 | 60 | Default prefersStatusBarHidden is NO, preferredStatusBarStyle is UIStatusBarStyleDefault. 61 | */ 62 | - (void)configureStatusBarAppearanceWithPrefersStatusBarHidden:(BOOL)prefersStatusBarHidden preferredStatusBarStyle:(NSInteger)preferredStatusBarStyle; 63 | 64 | /** 65 | Starts or resumes performance monitoring, initialize monitoring view if not initialized and shows monitoring view. Use configuration block to change appearance as you like. 66 | */ 67 | - (void)startMonitoringWithConfiguration:(void (^)(UILabel *textLabel))configuration; 68 | 69 | /** 70 | Starts or resumes performance monitoring, initialize monitoring view if not initialized and shows monitoring view. 71 | */ 72 | - (void)startMonitoring; 73 | 74 | /** 75 | Pauses performance monitoring and hides monitoring view. 76 | */ 77 | - (void)pauseMonitoring; 78 | 79 | /** 80 | Hides monitoring view. 81 | */ 82 | - (void)hideMonitoring; 83 | 84 | /** 85 | Stops and removes monitoring view. Call when you're done with performance monitoring. 86 | */ 87 | - (void)stopMonitoring; 88 | 89 | /** 90 | Use configuration block to change appearance as you like. 91 | */ 92 | - (void)configureWithConfiguration:(void (^)(UILabel *textLabel))configuration; 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /GDPerformanceView/GDPerformanceMonitoring/GDPerformanceMonitor.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import "GDPerformanceMonitor.h" 24 | 25 | #import "GDPerformanceView.h" 26 | 27 | @interface GDPerformanceMonitor () 28 | 29 | @property (nonatomic, strong) GDPerformanceView *performanceView; 30 | 31 | @property (nonatomic, getter=isPerformanceViewPaused) BOOL performanceViewPaused; 32 | 33 | @property (nonatomic, getter=isPerformanceViewHidden) BOOL performanceViewHidden; 34 | 35 | @property (nonatomic, getter=isPerformanceViewStopped) BOOL performanceViewStopped; 36 | 37 | @property (nonatomic) BOOL prefersStatusBarHidden; 38 | 39 | @property (nonatomic) UIStatusBarStyle preferredStatusBarStyle; 40 | 41 | @end 42 | 43 | @implementation GDPerformanceMonitor 44 | 45 | #pragma mark - 46 | #pragma mark - Init Methods & Superclass Overriders 47 | 48 | + (instancetype)sharedInstance { 49 | static id instance; 50 | static dispatch_once_t onceToken; 51 | dispatch_once(&onceToken, ^ { 52 | instance = [[self alloc] init]; 53 | }); 54 | return instance; 55 | } 56 | 57 | - (instancetype)init { 58 | self = [super init]; 59 | if (self) { 60 | [self subscribeToNotifications]; 61 | } 62 | return self; 63 | } 64 | 65 | - (void)dealloc { 66 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 67 | } 68 | 69 | #pragma mark - 70 | #pragma mark - Notifications & Observers 71 | 72 | - (void)applicationDidBecomeActive:(NSNotification *)notification { 73 | if (self.isPerformanceViewPaused) { 74 | return; 75 | } 76 | 77 | [self startOrResumeMonitoring]; 78 | } 79 | 80 | - (void)applicationWillResignActive:(NSNotification *)notification { 81 | [self.performanceView pauseMonitoring]; 82 | } 83 | 84 | #pragma mark - 85 | #pragma mark - Public Methods 86 | 87 | - (void)configureStatusBarAppearanceWithPrefersStatusBarHidden:(BOOL)prefersStatusBarHidden preferredStatusBarStyle:(NSInteger)preferredStatusBarStyle { 88 | self.prefersStatusBarHidden = prefersStatusBarHidden; 89 | self.preferredStatusBarStyle = preferredStatusBarStyle; 90 | 91 | [self checkAndApplyStatusBarAppearanceWithPrefersStatusBarHidden:prefersStatusBarHidden preferredStatusBarStyle:preferredStatusBarStyle]; 92 | } 93 | 94 | - (void)startMonitoringWithConfiguration:(void (^)(UILabel *))configuration { 95 | self.performanceViewPaused = NO; 96 | self.performanceViewHidden = NO; 97 | self.performanceViewStopped = NO; 98 | 99 | [self startOrResumeMonitoring]; 100 | 101 | if (configuration) { 102 | UILabel *textLabel = [self.performanceView textLabel]; 103 | configuration(textLabel); 104 | } 105 | } 106 | 107 | - (void)startMonitoring { 108 | self.performanceViewPaused = NO; 109 | self.performanceViewHidden = NO; 110 | self.performanceViewStopped = NO; 111 | 112 | [self startOrResumeMonitoring]; 113 | } 114 | 115 | - (void)pauseMonitoring { 116 | self.performanceViewPaused = YES; 117 | 118 | [self.performanceView pauseMonitoring]; 119 | } 120 | 121 | - (void)hideMonitoring { 122 | self.performanceViewHidden = YES; 123 | 124 | [self.performanceView hideMonitoring]; 125 | } 126 | 127 | - (void)stopMonitoring { 128 | self.performanceViewStopped = YES; 129 | 130 | [self.performanceView stopMonitoring]; 131 | self.performanceView = nil; 132 | } 133 | 134 | - (void)configureWithConfiguration:(void (^)(UILabel *))configuration { 135 | if (!self.performanceView) { 136 | return; 137 | } 138 | 139 | if (configuration) { 140 | UILabel *textLabel = [self.performanceView textLabel]; 141 | configuration(textLabel); 142 | } 143 | } 144 | 145 | #pragma mark - 146 | #pragma mark - Private Methods 147 | 148 | #pragma mark - Default Setups 149 | 150 | - (void)subscribeToNotifications { 151 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; 152 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil]; 153 | } 154 | 155 | #pragma mark - Monitoring 156 | 157 | - (void)startOrResumeMonitoring { 158 | if (!self.performanceView) { 159 | [self setupPerformanceView]; 160 | } else { 161 | [self.performanceView resumeMonitoringAndShowMonitoringView:!self.isPerformanceViewHidden]; 162 | } 163 | 164 | if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) { 165 | [self.performanceView addMonitoringViewAboveStatusBar]; 166 | } 167 | } 168 | 169 | - (void)setupPerformanceView { 170 | if (self.isPerformanceViewStopped) { 171 | return; 172 | } 173 | 174 | self.performanceView = [[GDPerformanceView alloc] init]; 175 | [self.performanceView setAppVersionHidden:self.appVersionHidden]; 176 | [self.performanceView setDeviceVersionHidden:self.deviceVersionHidden]; 177 | [self.performanceView setPerformanceDelegate:self.delegate]; 178 | [self checkAndApplyStatusBarAppearanceWithPrefersStatusBarHidden:self.prefersStatusBarHidden preferredStatusBarStyle:self.preferredStatusBarStyle]; 179 | 180 | if (self.isPerformanceViewPaused) { 181 | [self.performanceView pauseMonitoring]; 182 | } 183 | if (self.isPerformanceViewHidden) { 184 | [self.performanceView hideMonitoring]; 185 | } 186 | } 187 | 188 | #pragma mark - Other Methods 189 | 190 | - (void)checkAndApplyStatusBarAppearanceWithPrefersStatusBarHidden:(BOOL)prefersStatusBarHidden preferredStatusBarStyle:(UIStatusBarStyle)preferredStatusBarStyle { 191 | if (!self.performanceView) { 192 | return; 193 | } 194 | 195 | if (self.performanceView.prefersStatusBarHidden != prefersStatusBarHidden || self.performanceView.preferredStatusBarStyle != preferredStatusBarStyle) { 196 | self.performanceView.prefersStatusBarHidden = prefersStatusBarHidden; 197 | self.performanceView.preferredStatusBarStyle = preferredStatusBarStyle; 198 | 199 | [self.performanceView configureRootViewController]; 200 | } 201 | } 202 | 203 | #pragma mark - 204 | #pragma mark - Setters & Getters 205 | 206 | - (void)setDelegate:(id)delegate { 207 | _delegate = delegate; 208 | 209 | [self.performanceView setPerformanceDelegate:delegate]; 210 | } 211 | 212 | - (void)setAppVersionHidden:(BOOL)appVersionHidden { 213 | _appVersionHidden = appVersionHidden; 214 | 215 | if (self.performanceView) { 216 | [self.performanceView setAppVersionHidden:appVersionHidden]; 217 | } 218 | } 219 | 220 | - (void)setDeviceVersionHidden:(BOOL)deviceVersionHidden { 221 | _deviceVersionHidden = deviceVersionHidden; 222 | 223 | if (self.performanceView) { 224 | [self.performanceView setDeviceVersionHidden:deviceVersionHidden]; 225 | } 226 | } 227 | 228 | @end 229 | -------------------------------------------------------------------------------- /GDPerformanceView/GDPerformanceMonitoring/GDPerformanceMonitorProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import 24 | 25 | @protocol GDPerformanceMonitorDelegate 26 | 27 | - (void)performanceMonitorDidReportFPS:(int)fpsValue CPU:(float)cpuValue; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /GDPerformanceView/GDPerformanceMonitoring/GDPerformanceView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import 24 | 25 | #import "GDPerformanceMonitorProtocol.h" 26 | 27 | @interface GDPerformanceView : UIWindow 28 | 29 | /** 30 | GDPerformanceMonitorDelegate delegate. 31 | */ 32 | @property (nonatomic, weak) id performanceDelegate; 33 | 34 | /** 35 | Change it to hide or show application version from monitoring view. Default is NO. 36 | */ 37 | @property (nonatomic, getter=isAppVersionHidden) BOOL appVersionHidden; 38 | 39 | /** 40 | Change it to hide or show device iOS version from monitoring view. Default is NO. 41 | */ 42 | @property (nonatomic, getter=isDeviceVersionHidden) BOOL deviceVersionHidden; 43 | 44 | /** 45 | Override this properties to return the desired status bar attributes. 46 | 47 | Default prefersStatusBarHidden is false, preferredStatusBarStyle is UIStatusBarStyle.default. 48 | */ 49 | @property (nonatomic) BOOL prefersStatusBarHidden; 50 | 51 | @property (nonatomic) UIStatusBarStyle preferredStatusBarStyle; 52 | 53 | 54 | /** 55 | Returns weak monitoring text label. 56 | */ 57 | - (UILabel *)textLabel; 58 | 59 | /** 60 | Pauses performance monitoring and hides monitoring view. 61 | */ 62 | - (void)pauseMonitoring; 63 | 64 | /** 65 | Resumes performance monitoring and shows monitoring view. 66 | */ 67 | - (void)resumeMonitoringAndShowMonitoringView:(BOOL)showMonitoringView; 68 | 69 | /** 70 | Hides monitoring view. 71 | */ 72 | - (void)hideMonitoring; 73 | 74 | /** 75 | Adds monitoring view above the status bar. 76 | */ 77 | - (void)addMonitoringViewAboveStatusBar; 78 | 79 | /** 80 | Configures root view controller with prefersStatusBarHidden and preferredStatusBarStyle. 81 | */ 82 | - (void)configureRootViewController; 83 | 84 | /** 85 | Stops and removes monitoring view. Call when you're done with performance monitoring. 86 | */ 87 | - (void)stopMonitoring; 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /GDPerformanceView/GDPerformanceMonitoring/GDPerformanceView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import "GDPerformanceView.h" 24 | 25 | #import 26 | #import 27 | 28 | #import "GDMarginLabel.h" 29 | #import "GDWindowViewController.h" 30 | 31 | @interface GDPerformanceView () 32 | 33 | @property (nonatomic, strong) CADisplayLink *displayLink; 34 | 35 | @property (nonatomic, strong) GDMarginLabel *monitoringTextLabel; 36 | 37 | @property (nonatomic) int screenUpdatesCount; 38 | 39 | @property (nonatomic) CFTimeInterval screenUpdatesBeginTime; 40 | 41 | @property (nonatomic) CFTimeInterval averageScreenUpdatesTime; 42 | 43 | @property (nonatomic) NSString *versionsString; 44 | 45 | @end 46 | 47 | @implementation GDPerformanceView 48 | 49 | #pragma mark - 50 | #pragma mark - Init Methods & Superclass Overriders 51 | 52 | - (instancetype)init { 53 | self = [super initWithFrame:[GDPerformanceView windowFrame]]; 54 | if (self) { 55 | [self setupWindowAndDefaultVariables]; 56 | [self setupDisplayLink]; 57 | [self setupTextLayers]; 58 | [self subscribeToNotifications]; 59 | [self configureVersionsString]; 60 | } 61 | return self; 62 | } 63 | 64 | - (void)layoutSubviews { 65 | [super layoutSubviews]; 66 | 67 | [self layoutWindow]; 68 | } 69 | 70 | - (void)becomeKeyWindow { 71 | [self setHidden:YES]; 72 | 73 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 74 | [self setHidden:NO]; 75 | }); 76 | } 77 | 78 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { 79 | return NO; 80 | } 81 | 82 | - (void)dealloc { 83 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 84 | } 85 | 86 | #pragma mark - 87 | #pragma mark - Notifications & Observers 88 | 89 | - (void)applicationWillChangeStatusBarFrame:(NSNotification *)notification { 90 | dispatch_async(dispatch_get_main_queue(), ^{ 91 | [self layoutWindow]; 92 | }); 93 | } 94 | 95 | #pragma mark - 96 | #pragma mark - Public Methods 97 | 98 | - (UILabel *)textLabel { 99 | __weak UILabel *weakTextLabel = self.monitoringTextLabel; 100 | return weakTextLabel; 101 | } 102 | 103 | - (void)pauseMonitoring { 104 | [self.displayLink setPaused:YES]; 105 | 106 | [self.monitoringTextLabel removeFromSuperview]; 107 | } 108 | 109 | - (void)resumeMonitoringAndShowMonitoringView:(BOOL)showMonitoringView { 110 | [self.displayLink setPaused:NO]; 111 | 112 | if (showMonitoringView) { 113 | [self addSubview:self.monitoringTextLabel]; 114 | } 115 | } 116 | 117 | - (void)hideMonitoring { 118 | [self.monitoringTextLabel removeFromSuperview]; 119 | } 120 | 121 | - (void)addMonitoringViewAboveStatusBar { 122 | if (![self isHidden]) { 123 | return; 124 | } 125 | 126 | [self setHidden:NO]; 127 | } 128 | 129 | - (void)configureRootViewController { 130 | GDWindowViewController *rootViewController = [[GDWindowViewController alloc] init]; 131 | [rootViewController configureStatusBarAppearanceWithPrefersStatusBarHidden:self.prefersStatusBarHidden preferredStatusBarStyle:self.preferredStatusBarStyle]; 132 | 133 | self.rootViewController = rootViewController; 134 | } 135 | 136 | - (void)stopMonitoring { 137 | [self.displayLink invalidate]; 138 | self.displayLink = nil; 139 | } 140 | 141 | #pragma mark - 142 | #pragma mark - Private Methods 143 | 144 | #pragma mark - Default Setups 145 | 146 | - (void)setupWindowAndDefaultVariables { 147 | self.prefersStatusBarHidden = NO; 148 | self.preferredStatusBarStyle = UIStatusBarStyleDefault; 149 | self.screenUpdatesCount = 0; 150 | self.screenUpdatesBeginTime = 0.0f; 151 | self.averageScreenUpdatesTime = 0.017f; 152 | 153 | GDWindowViewController *rootViewController = [[GDWindowViewController alloc] init]; 154 | 155 | [self setRootViewController:rootViewController]; 156 | [self setWindowLevel:(UIWindowLevelStatusBar + 1.0f)]; 157 | [self setBackgroundColor:[UIColor clearColor]]; 158 | [self setClipsToBounds:YES]; 159 | [self setHidden:YES]; 160 | } 161 | 162 | - (void)setupDisplayLink { 163 | self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkAction:)]; 164 | [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 165 | } 166 | 167 | - (void)setupTextLayers { 168 | self.monitoringTextLabel = [[GDMarginLabel alloc] init]; 169 | [self.monitoringTextLabel setTextAlignment:NSTextAlignmentCenter]; 170 | [self.monitoringTextLabel setNumberOfLines:2]; 171 | [self.monitoringTextLabel setBackgroundColor:[UIColor blackColor]]; 172 | [self.monitoringTextLabel setTextColor:[UIColor whiteColor]]; 173 | [self.monitoringTextLabel setClipsToBounds:YES]; 174 | [self.monitoringTextLabel setFont:[UIFont systemFontOfSize:8.0f]]; 175 | [self.monitoringTextLabel.layer setBorderWidth:1.0f]; 176 | [self.monitoringTextLabel.layer setBorderColor:[[UIColor blackColor] CGColor]]; 177 | [self.monitoringTextLabel.layer setCornerRadius:5.0f]; 178 | 179 | [self addSubview:self.monitoringTextLabel]; 180 | } 181 | 182 | - (void)subscribeToNotifications { 183 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillChangeStatusBarFrame:) name:UIApplicationWillChangeStatusBarFrameNotification object:nil]; 184 | } 185 | 186 | #pragma mark - Monitoring 187 | 188 | - (void)displayLinkAction:(CADisplayLink *)displayLink { 189 | if (self.screenUpdatesBeginTime == 0.0f) { 190 | self.screenUpdatesBeginTime = displayLink.timestamp; 191 | } else { 192 | self.screenUpdatesCount += 1; 193 | 194 | CFTimeInterval screenUpdatesTime = self.displayLink.timestamp - self.screenUpdatesBeginTime; 195 | 196 | if (screenUpdatesTime >= 1.0) { 197 | CFTimeInterval updatesOverSecond = screenUpdatesTime - 1.0f; 198 | int framesOverSecond = updatesOverSecond / self.averageScreenUpdatesTime; 199 | 200 | self.screenUpdatesCount -= framesOverSecond; 201 | if (self.screenUpdatesCount < 0) { 202 | self.screenUpdatesCount = 0; 203 | } 204 | 205 | [self takeReadings]; 206 | } 207 | } 208 | } 209 | 210 | - (void)takeReadings { 211 | int fps = self.screenUpdatesCount; 212 | float cpu = [self cpuUsage]; 213 | 214 | self.screenUpdatesCount = 0; 215 | self.screenUpdatesBeginTime = 0.0f; 216 | 217 | [self reportFPS:fps CPU:cpu]; 218 | [self updateMonitoringLabelWithFPS:fps CPU:cpu]; 219 | } 220 | 221 | - (float)cpuUsage { 222 | kern_return_t kern; 223 | 224 | thread_array_t threadList; 225 | mach_msg_type_number_t threadCount; 226 | 227 | thread_info_data_t threadInfo; 228 | mach_msg_type_number_t threadInfoCount; 229 | 230 | thread_basic_info_t threadBasicInfo; 231 | uint32_t threadStatistic = 0; 232 | 233 | kern = task_threads(mach_task_self(), &threadList, &threadCount); 234 | if (kern != KERN_SUCCESS) { 235 | return -1; 236 | } 237 | if (threadCount > 0) { 238 | threadStatistic += threadCount; 239 | } 240 | 241 | float totalUsageOfCPU = 0; 242 | 243 | for (int i = 0; i < threadCount; i++) { 244 | threadInfoCount = THREAD_INFO_MAX; 245 | kern = thread_info(threadList[i], THREAD_BASIC_INFO, (thread_info_t)threadInfo, &threadInfoCount); 246 | if (kern != KERN_SUCCESS) { 247 | return -1; 248 | } 249 | 250 | threadBasicInfo = (thread_basic_info_t)threadInfo; 251 | 252 | if (!(threadBasicInfo -> flags & TH_FLAGS_IDLE)) { 253 | totalUsageOfCPU = totalUsageOfCPU + threadBasicInfo -> cpu_usage / (float)TH_USAGE_SCALE * 100.0f; 254 | } 255 | } 256 | 257 | kern = vm_deallocate(mach_task_self(), (vm_offset_t)threadList, threadCount * sizeof(thread_t)); 258 | 259 | return totalUsageOfCPU; 260 | } 261 | 262 | #pragma mark - Other Methods 263 | 264 | + (CGRect)windowFrame { 265 | CGRect frame = CGRectZero; 266 | UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 267 | if (window) { 268 | frame = CGRectMake(0.0f, 0.0f, CGRectGetWidth(window.bounds), 20.0f); 269 | } 270 | return frame; 271 | } 272 | 273 | - (void)reportFPS:(int)fpsValue CPU:(float)cpuValue { 274 | if (!self.performanceDelegate || ![self.performanceDelegate respondsToSelector:@selector(performanceMonitorDidReportFPS:CPU:)]) { 275 | return; 276 | } 277 | 278 | [self.performanceDelegate performanceMonitorDidReportFPS:fpsValue CPU:cpuValue]; 279 | } 280 | 281 | - (void)updateMonitoringLabelWithFPS:(int)fpsValue CPU:(float)cpuValue { 282 | NSString *monitoringString = [NSString stringWithFormat:@"FPS : %d CPU : %.1f%%%@", fpsValue, cpuValue, self.versionsString]; 283 | 284 | [self.monitoringTextLabel setText:monitoringString]; 285 | [self layoutTextLabel]; 286 | } 287 | 288 | - (void)layoutTextLabel { 289 | CGFloat windowWidth = CGRectGetWidth(self.bounds); 290 | CGFloat windowHeight = CGRectGetHeight(self.bounds); 291 | CGSize labelSize = [self.monitoringTextLabel sizeThatFits:CGSizeMake(windowWidth, windowHeight)]; 292 | 293 | [self.monitoringTextLabel setFrame:CGRectMake((windowWidth - labelSize.width) / 2.0f, (windowHeight - labelSize.height) / 2.0f, labelSize.width, labelSize.height)]; 294 | } 295 | 296 | - (void)layoutWindow { 297 | [self setFrame:[GDPerformanceView windowFrame]]; 298 | [self layoutTextLabel]; 299 | } 300 | 301 | - (void)configureVersionsString { 302 | if (!self.appVersionHidden || !self.deviceVersionHidden) { 303 | NSString *applicationVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; 304 | NSString *applicationBuild = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; 305 | NSString *systemVersion = [[UIDevice currentDevice] systemVersion]; 306 | 307 | if (!self.appVersionHidden && !self.deviceVersionHidden) { 308 | self.versionsString = [NSString stringWithFormat:@"\napp v%@ (%@) iOS v%@", applicationVersion, applicationBuild, systemVersion]; 309 | } else if (!self.appVersionHidden) { 310 | self.versionsString = [NSString stringWithFormat:@"\napp v%@ (%@)", applicationVersion, applicationBuild]; 311 | } else if (!self.deviceVersionHidden) { 312 | self.versionsString = [NSString stringWithFormat:@"\niOS v%@", systemVersion]; 313 | } 314 | } else { 315 | self.versionsString = @""; 316 | } 317 | } 318 | 319 | #pragma mark - 320 | #pragma mark - Setters & Getters 321 | 322 | - (void)setAppVersionHidden:(BOOL)appVersionHidden { 323 | if (appVersionHidden == _appVersionHidden) { 324 | return; 325 | } 326 | 327 | _appVersionHidden = appVersionHidden; 328 | 329 | [self configureVersionsString]; 330 | } 331 | 332 | - (void)setDeviceVersionHidden:(BOOL)deviceVersionHidden { 333 | if (deviceVersionHidden == _deviceVersionHidden) { 334 | return; 335 | } 336 | 337 | _deviceVersionHidden = deviceVersionHidden; 338 | 339 | [self configureVersionsString]; 340 | } 341 | 342 | @end 343 | -------------------------------------------------------------------------------- /GDPerformanceView/GDPerformanceMonitoring/GDWindowViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import 24 | 25 | @interface GDWindowViewController : UIViewController 26 | 27 | - (void)configureStatusBarAppearanceWithPrefersStatusBarHidden:(BOOL)prefersStatusBarHidden preferredStatusBarStyle:(UIStatusBarStyle)preferredStatusBarStyle; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /GDPerformanceView/GDPerformanceMonitoring/GDWindowViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import "GDWindowViewController.h" 24 | 25 | @interface GDWindowViewController () 26 | 27 | @property (nonatomic) BOOL selectedStatusBarHidden; 28 | 29 | @property (nonatomic) UIStatusBarStyle selectedStatusBarStyle; 30 | 31 | @end 32 | 33 | @implementation GDWindowViewController 34 | 35 | #pragma mark - 36 | #pragma mark - Init Methods & Superclass Overriders 37 | 38 | - (instancetype)init { 39 | self = [super init]; 40 | if (self) { 41 | [self setSelectedStatusBarHidden:NO]; 42 | [self setSelectedStatusBarStyle:UIStatusBarStyleDefault]; 43 | } 44 | return self; 45 | } 46 | 47 | - (void)viewDidLoad { 48 | [super viewDidLoad]; 49 | 50 | [self.view setBackgroundColor:[UIColor clearColor]]; 51 | } 52 | 53 | - (void)didReceiveMemoryWarning { 54 | [super didReceiveMemoryWarning]; 55 | } 56 | 57 | - (BOOL)prefersStatusBarHidden { 58 | return self.selectedStatusBarHidden; 59 | } 60 | 61 | - (UIStatusBarStyle)preferredStatusBarStyle { 62 | return self.selectedStatusBarStyle; 63 | } 64 | 65 | #pragma mark - 66 | #pragma mark - Public Methods 67 | 68 | - (void)configureStatusBarAppearanceWithPrefersStatusBarHidden:(BOOL)prefersStatusBarHidden preferredStatusBarStyle:(UIStatusBarStyle)preferredStatusBarStyle { 69 | self.selectedStatusBarHidden = prefersStatusBarHidden; 70 | self.selectedStatusBarStyle = preferredStatusBarStyle; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /GDPerformanceView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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.3.1 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 | UIInterfaceOrientationPortraitUpsideDown 37 | 38 | UISupportedInterfaceOrientations~ipad 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationPortraitUpsideDown 42 | UIInterfaceOrientationLandscapeLeft 43 | UIInterfaceOrientationLandscapeRight 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /GDPerformanceView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Gavrilov Daniil 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #import 24 | #import "AppDelegate.h" 25 | 26 | int main(int argc, char * argv[]) { 27 | @autoreleasepool { 28 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Gavrilov Daniil 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 NON INFRINGEMENT. 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #GDPerformanceView 2 | Shows FPS, CPU usage, app and iOS versions above the status bar and report FPS and CPU usage via delegate. 3 | 4 | [![Pod Version](https://img.shields.io/badge/Pod-1.3.1-6193DF.svg)](https://cocoapods.org/) 5 | ![Swift Version](https://img.shields.io/badge/xCode-8.2+-blue.svg) 6 | ![Swift Version](https://img.shields.io/badge/iOS-8.0+-blue.svg) 7 | ![Plaform](https://img.shields.io/badge/Platform-iOS-lightgrey.svg) 8 | ![License MIT](https://img.shields.io/badge/License-MIT-lightgrey.svg) 9 | 10 | ![Alt text](https://github.com/dani-gavrilov/GDPerformanceView/blob/master/performance_view.PNG?raw=true "Example PNG") 11 | ![Alt text](https://github.com/dani-gavrilov/GDPerformanceView/blob/master/performance_view_2.PNG?raw=true "Example PNG") 12 | ![Alt text](https://github.com/dani-gavrilov/GDPerformanceView/blob/master/performance_view_3.PNG?raw=true "Example PNG") 13 | ![Alt text](https://github.com/dani-gavrilov/GDPerformanceView/blob/master/performance_view_4.PNG?raw=true "Example PNG") 14 | 15 | ## Installation 16 | Simply add GDPerformanceMonitoring folder with files to your project, or use CocoaPods. 17 | 18 | #### Podfile 19 | You can use [CocoaPods](http://cocoapods.org/) to install `GDPerformanceView` by adding it to your `Podfile`: 20 | 21 | ```ruby 22 | platform :ios, '8.0' 23 | use_frameworks! 24 | 25 | target 'project_name' do 26 | pod 'GDPerformanceView', '~> 1.3.1' 27 | end 28 | ``` 29 | Don't forget to import GDPerformanceView by adding: 30 | 31 | ```objective-c 32 | #import 33 | ``` 34 | 35 | ## Usage example 36 | 37 | Simply start monitoring. Performance view will be added above the status bar automatically. 38 | Also, you can configure appearance as you like or just hide the monitoring view and use its delegate. 39 | 40 | #### Start monitoring 41 | 42 | Call to start or resume monitoring and show monitoring view. 43 | 44 | ```objective-c 45 | [[GDPerformanceMonitor sharedInstance] startMonitoring]; 46 | ``` 47 | 48 | ```objective-c 49 | self.performanceMonitor = [GDPerformanceMonitor alloc] init]; 50 | [self.performanceMonitor startMonitoring]; 51 | ``` 52 | 53 | #### Stop monitoring 54 | 55 | Call when you're done with performance monitoring. 56 | 57 | ```objective-c 58 | [self.performanceMonitor stopMonitoring]; 59 | ``` 60 | 61 | Call to hide and pause monitoring. 62 | 63 | ```objective-c 64 | [self.performanceMonitor pauseMonitoring]; 65 | ``` 66 | 67 | #### Configuration 68 | 69 | Call to change appearance. 70 | 71 | ```objective-c 72 | [self.performanceMonitor configureWithConfiguration:^(UILabel *textLabel) { 73 | [textLabel setBackgroundColor:[UIColor blackColor]]; 74 | [textLabel setTextColor:[UIColor whiteColor]]; 75 | [textLabel.layer setBorderColor:[[UIColor blackColor] CGColor]]; 76 | }]; 77 | ``` 78 | 79 | Call to change output information. 80 | 81 | ```objective-c 82 | [self.performanceMonitor setAppVersionHidden:YES] 83 | ``` 84 | ```objective-c 85 | [self.performanceMonitor setDeviceVersionHidden:YES]; 86 | ``` 87 | 88 | Call to hide monitoring view. 89 | 90 | ```objective-c 91 | [self.performanceMonitor hideMonitoring]; 92 | ``` 93 | 94 | Call to change status bar appearance. 95 | 96 | ```objective-c 97 | [self.performanceMonitor configureStatusBarAppearanceWithPrefersStatusBarHidden:NO preferredStatusBarStyle:UIStatusBarStyleLightContent]; 98 | ``` 99 | 100 | #### Start monitoring and configure 101 | 102 | ```objective-c 103 | [self.performanceMonitor startMonitoringWithConfiguration:^(UILabel *textLabel) { 104 | [textLabel setBackgroundColor:[UIColor blackColor]]; 105 | [textLabel setTextColor:[UIColor whiteColor]]; 106 | [textLabel.layer setBorderColor:[[UIColor blackColor] CGColor]]; 107 | }]; 108 | ``` 109 | 110 | #### Delegate 111 | 112 | Set the delegate and implement its method. 113 | 114 | ```objective-c 115 | [self.performanceMonitor setDelegate:self]; 116 | ``` 117 | 118 | ```objective-c 119 | - (void)performanceMonitorDidReportFPS:(int)fpsValue CPU:(float)cpuValue { 120 | NSLog(@"%d %f", fpsValue, cpuValue); 121 | } 122 | ``` 123 | 124 | ## Requirements 125 | - iOS 8.0+ 126 | - xCode 8.2+ 127 | 128 | ## Meta 129 | 130 | Daniil Gavrilov - [VK](https://vk.com/dani_gavrilov) - [FB](https://www.facebook.com/danigavrilov) 131 | 132 | GDPerformanceView is available under the MIT license. See the LICENSE file for more info. 133 | -------------------------------------------------------------------------------- /performance_view.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dani-gavrilov/GDPerformanceView/0cd10a2bda63e371bd7edc9e74e497bce3336951/performance_view.PNG -------------------------------------------------------------------------------- /performance_view_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dani-gavrilov/GDPerformanceView/0cd10a2bda63e371bd7edc9e74e497bce3336951/performance_view_2.PNG -------------------------------------------------------------------------------- /performance_view_3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dani-gavrilov/GDPerformanceView/0cd10a2bda63e371bd7edc9e74e497bce3336951/performance_view_3.PNG -------------------------------------------------------------------------------- /performance_view_4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dani-gavrilov/GDPerformanceView/0cd10a2bda63e371bd7edc9e74e497bce3336951/performance_view_4.PNG --------------------------------------------------------------------------------