├── Image └── screenshot-instruments.png ├── MeasuringPerformanceDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── a14770.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── a14770.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── MeasuringPerformanceDemo ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ImageDownloader.swift ├── ImageTableViewCell.swift ├── ImageTableViewCell.xib ├── ImageURL.swift ├── Info.plist ├── OSLogExtension.swift ├── PhotoViewController.swift ├── PhotoViewController.xib └── TableViewController.swift └── README.md /Image/screenshot-instruments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shoheiyokoyama/DebuggingPerformance/d19d78480cfd250eb1bf0075b5f14da8961cd432/Image/screenshot-instruments.png -------------------------------------------------------------------------------- /MeasuringPerformanceDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E002820120D806F100CFDEAF /* PhotoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E002820020D806F100CFDEAF /* PhotoViewController.swift */; }; 11 | E0884E6720D63CAD00ECD193 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0884E6620D63CAD00ECD193 /* AppDelegate.swift */; }; 12 | E0884E6C20D63CAD00ECD193 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E0884E6A20D63CAD00ECD193 /* Main.storyboard */; }; 13 | E0884E6E20D63CAF00ECD193 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E0884E6D20D63CAF00ECD193 /* Assets.xcassets */; }; 14 | E0884E7120D63CAF00ECD193 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E0884E6F20D63CAF00ECD193 /* LaunchScreen.storyboard */; }; 15 | E0884E7920D63CF200ECD193 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0884E7820D63CF200ECD193 /* TableViewController.swift */; }; 16 | E0884E7C20D63E4600ECD193 /* ImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0884E7A20D63E4600ECD193 /* ImageTableViewCell.swift */; }; 17 | E0884E7D20D63E4600ECD193 /* ImageTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = E0884E7B20D63E4600ECD193 /* ImageTableViewCell.xib */; }; 18 | E0884E7F20D6525F00ECD193 /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0884E7E20D6525F00ECD193 /* ImageDownloader.swift */; }; 19 | E0922BD220D69D18005DE949 /* ImageURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0922BD120D69D18005DE949 /* ImageURL.swift */; }; 20 | E0A52A0220D80D0B00416B78 /* OSLogExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0A52A0120D80D0B00416B78 /* OSLogExtension.swift */; }; 21 | E0A933F120D80B72001C7254 /* PhotoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E0A933F020D80B72001C7254 /* PhotoViewController.xib */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | E002820020D806F100CFDEAF /* PhotoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoViewController.swift; sourceTree = ""; }; 26 | E0884E6320D63CAD00ECD193 /* MeasuringPerformanceDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MeasuringPerformanceDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | E0884E6620D63CAD00ECD193 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 28 | E0884E6B20D63CAD00ECD193 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | E0884E6D20D63CAF00ECD193 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | E0884E7020D63CAF00ECD193 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | E0884E7220D63CAF00ECD193 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | E0884E7820D63CF200ECD193 /* TableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; 33 | E0884E7A20D63E4600ECD193 /* ImageTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTableViewCell.swift; sourceTree = ""; }; 34 | E0884E7B20D63E4600ECD193 /* ImageTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ImageTableViewCell.xib; sourceTree = ""; }; 35 | E0884E7E20D6525F00ECD193 /* ImageDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDownloader.swift; sourceTree = ""; }; 36 | E0922BD120D69D18005DE949 /* ImageURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageURL.swift; sourceTree = ""; }; 37 | E0A52A0120D80D0B00416B78 /* OSLogExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSLogExtension.swift; sourceTree = ""; }; 38 | E0A933F020D80B72001C7254 /* PhotoViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PhotoViewController.xib; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | E0884E6020D63CAD00ECD193 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | E0884E5A20D63CAD00ECD193 = { 53 | isa = PBXGroup; 54 | children = ( 55 | E0884E6520D63CAD00ECD193 /* MeasuringPerformanceDemo */, 56 | E0884E6420D63CAD00ECD193 /* Products */, 57 | ); 58 | sourceTree = ""; 59 | }; 60 | E0884E6420D63CAD00ECD193 /* Products */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | E0884E6320D63CAD00ECD193 /* MeasuringPerformanceDemo.app */, 64 | ); 65 | name = Products; 66 | sourceTree = ""; 67 | }; 68 | E0884E6520D63CAD00ECD193 /* MeasuringPerformanceDemo */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | E0884E6620D63CAD00ECD193 /* AppDelegate.swift */, 72 | E0884E6A20D63CAD00ECD193 /* Main.storyboard */, 73 | E0884E6D20D63CAF00ECD193 /* Assets.xcassets */, 74 | E0884E6F20D63CAF00ECD193 /* LaunchScreen.storyboard */, 75 | E0884E7220D63CAF00ECD193 /* Info.plist */, 76 | E0884E7E20D6525F00ECD193 /* ImageDownloader.swift */, 77 | E0884E7A20D63E4600ECD193 /* ImageTableViewCell.swift */, 78 | E0884E7B20D63E4600ECD193 /* ImageTableViewCell.xib */, 79 | E0922BD120D69D18005DE949 /* ImageURL.swift */, 80 | E0A52A0120D80D0B00416B78 /* OSLogExtension.swift */, 81 | E002820020D806F100CFDEAF /* PhotoViewController.swift */, 82 | E0A933F020D80B72001C7254 /* PhotoViewController.xib */, 83 | E0884E7820D63CF200ECD193 /* TableViewController.swift */, 84 | ); 85 | path = MeasuringPerformanceDemo; 86 | sourceTree = ""; 87 | }; 88 | /* End PBXGroup section */ 89 | 90 | /* Begin PBXNativeTarget section */ 91 | E0884E6220D63CAD00ECD193 /* MeasuringPerformanceDemo */ = { 92 | isa = PBXNativeTarget; 93 | buildConfigurationList = E0884E7520D63CAF00ECD193 /* Build configuration list for PBXNativeTarget "MeasuringPerformanceDemo" */; 94 | buildPhases = ( 95 | E0884E5F20D63CAD00ECD193 /* Sources */, 96 | E0884E6020D63CAD00ECD193 /* Frameworks */, 97 | E0884E6120D63CAD00ECD193 /* Resources */, 98 | ); 99 | buildRules = ( 100 | ); 101 | dependencies = ( 102 | ); 103 | name = MeasuringPerformanceDemo; 104 | productName = MeasuringPerformanceDemo; 105 | productReference = E0884E6320D63CAD00ECD193 /* MeasuringPerformanceDemo.app */; 106 | productType = "com.apple.product-type.application"; 107 | }; 108 | /* End PBXNativeTarget section */ 109 | 110 | /* Begin PBXProject section */ 111 | E0884E5B20D63CAD00ECD193 /* Project object */ = { 112 | isa = PBXProject; 113 | attributes = { 114 | LastSwiftUpdateCheck = 1000; 115 | LastUpgradeCheck = 1000; 116 | ORGANIZATIONNAME = shoheiyokoyama; 117 | TargetAttributes = { 118 | E0884E6220D63CAD00ECD193 = { 119 | CreatedOnToolsVersion = 10.0; 120 | LastSwiftMigration = 1130; 121 | }; 122 | }; 123 | }; 124 | buildConfigurationList = E0884E5E20D63CAD00ECD193 /* Build configuration list for PBXProject "MeasuringPerformanceDemo" */; 125 | compatibilityVersion = "Xcode 9.3"; 126 | developmentRegion = en; 127 | hasScannedForEncodings = 0; 128 | knownRegions = ( 129 | en, 130 | Base, 131 | ); 132 | mainGroup = E0884E5A20D63CAD00ECD193; 133 | productRefGroup = E0884E6420D63CAD00ECD193 /* Products */; 134 | projectDirPath = ""; 135 | projectRoot = ""; 136 | targets = ( 137 | E0884E6220D63CAD00ECD193 /* MeasuringPerformanceDemo */, 138 | ); 139 | }; 140 | /* End PBXProject section */ 141 | 142 | /* Begin PBXResourcesBuildPhase section */ 143 | E0884E6120D63CAD00ECD193 /* Resources */ = { 144 | isa = PBXResourcesBuildPhase; 145 | buildActionMask = 2147483647; 146 | files = ( 147 | E0884E7120D63CAF00ECD193 /* LaunchScreen.storyboard in Resources */, 148 | E0A933F120D80B72001C7254 /* PhotoViewController.xib in Resources */, 149 | E0884E7D20D63E4600ECD193 /* ImageTableViewCell.xib in Resources */, 150 | E0884E6E20D63CAF00ECD193 /* Assets.xcassets in Resources */, 151 | E0884E6C20D63CAD00ECD193 /* Main.storyboard in Resources */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXResourcesBuildPhase section */ 156 | 157 | /* Begin PBXSourcesBuildPhase section */ 158 | E0884E5F20D63CAD00ECD193 /* Sources */ = { 159 | isa = PBXSourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | E0922BD220D69D18005DE949 /* ImageURL.swift in Sources */, 163 | E0A52A0220D80D0B00416B78 /* OSLogExtension.swift in Sources */, 164 | E0884E7C20D63E4600ECD193 /* ImageTableViewCell.swift in Sources */, 165 | E0884E7920D63CF200ECD193 /* TableViewController.swift in Sources */, 166 | E0884E7F20D6525F00ECD193 /* ImageDownloader.swift in Sources */, 167 | E0884E6720D63CAD00ECD193 /* AppDelegate.swift in Sources */, 168 | E002820120D806F100CFDEAF /* PhotoViewController.swift in Sources */, 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | /* End PBXSourcesBuildPhase section */ 173 | 174 | /* Begin PBXVariantGroup section */ 175 | E0884E6A20D63CAD00ECD193 /* Main.storyboard */ = { 176 | isa = PBXVariantGroup; 177 | children = ( 178 | E0884E6B20D63CAD00ECD193 /* Base */, 179 | ); 180 | name = Main.storyboard; 181 | sourceTree = ""; 182 | }; 183 | E0884E6F20D63CAF00ECD193 /* LaunchScreen.storyboard */ = { 184 | isa = PBXVariantGroup; 185 | children = ( 186 | E0884E7020D63CAF00ECD193 /* Base */, 187 | ); 188 | name = LaunchScreen.storyboard; 189 | sourceTree = ""; 190 | }; 191 | /* End PBXVariantGroup section */ 192 | 193 | /* Begin XCBuildConfiguration section */ 194 | E0884E7320D63CAF00ECD193 /* Debug */ = { 195 | isa = XCBuildConfiguration; 196 | buildSettings = { 197 | ALWAYS_SEARCH_USER_PATHS = NO; 198 | CLANG_ANALYZER_NONNULL = YES; 199 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 200 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 201 | CLANG_CXX_LIBRARY = "libc++"; 202 | CLANG_ENABLE_MODULES = YES; 203 | CLANG_ENABLE_OBJC_ARC = YES; 204 | CLANG_ENABLE_OBJC_WEAK = YES; 205 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 206 | CLANG_WARN_BOOL_CONVERSION = YES; 207 | CLANG_WARN_COMMA = YES; 208 | CLANG_WARN_CONSTANT_CONVERSION = YES; 209 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 212 | CLANG_WARN_EMPTY_BODY = YES; 213 | CLANG_WARN_ENUM_CONVERSION = YES; 214 | CLANG_WARN_INFINITE_RECURSION = YES; 215 | CLANG_WARN_INT_CONVERSION = YES; 216 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 217 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 218 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 219 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 220 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 221 | CLANG_WARN_STRICT_PROTOTYPES = YES; 222 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 223 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 224 | CLANG_WARN_UNREACHABLE_CODE = YES; 225 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 226 | CODE_SIGN_IDENTITY = "iPhone Developer"; 227 | COPY_PHASE_STRIP = NO; 228 | DEBUG_INFORMATION_FORMAT = dwarf; 229 | ENABLE_STRICT_OBJC_MSGSEND = YES; 230 | ENABLE_TESTABILITY = YES; 231 | GCC_C_LANGUAGE_STANDARD = gnu11; 232 | GCC_DYNAMIC_NO_PIC = NO; 233 | GCC_NO_COMMON_BLOCKS = YES; 234 | GCC_OPTIMIZATION_LEVEL = 0; 235 | GCC_PREPROCESSOR_DEFINITIONS = ( 236 | "DEBUG=1", 237 | "$(inherited)", 238 | ); 239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 241 | GCC_WARN_UNDECLARED_SELECTOR = YES; 242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 243 | GCC_WARN_UNUSED_FUNCTION = YES; 244 | GCC_WARN_UNUSED_VARIABLE = YES; 245 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 246 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 247 | ONLY_ACTIVE_ARCH = YES; 248 | SDKROOT = iphoneos; 249 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 250 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 251 | }; 252 | name = Debug; 253 | }; 254 | E0884E7420D63CAF00ECD193 /* Release */ = { 255 | isa = XCBuildConfiguration; 256 | buildSettings = { 257 | ALWAYS_SEARCH_USER_PATHS = NO; 258 | CLANG_ANALYZER_NONNULL = YES; 259 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 261 | CLANG_CXX_LIBRARY = "libc++"; 262 | CLANG_ENABLE_MODULES = YES; 263 | CLANG_ENABLE_OBJC_ARC = YES; 264 | CLANG_ENABLE_OBJC_WEAK = YES; 265 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 266 | CLANG_WARN_BOOL_CONVERSION = YES; 267 | CLANG_WARN_COMMA = YES; 268 | CLANG_WARN_CONSTANT_CONVERSION = YES; 269 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 270 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 271 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 272 | CLANG_WARN_EMPTY_BODY = YES; 273 | CLANG_WARN_ENUM_CONVERSION = YES; 274 | CLANG_WARN_INFINITE_RECURSION = YES; 275 | CLANG_WARN_INT_CONVERSION = YES; 276 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 277 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 278 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 279 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 280 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 281 | CLANG_WARN_STRICT_PROTOTYPES = YES; 282 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 283 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 284 | CLANG_WARN_UNREACHABLE_CODE = YES; 285 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 286 | CODE_SIGN_IDENTITY = "iPhone Developer"; 287 | COPY_PHASE_STRIP = NO; 288 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 289 | ENABLE_NS_ASSERTIONS = NO; 290 | ENABLE_STRICT_OBJC_MSGSEND = YES; 291 | GCC_C_LANGUAGE_STANDARD = gnu11; 292 | GCC_NO_COMMON_BLOCKS = YES; 293 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 294 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 295 | GCC_WARN_UNDECLARED_SELECTOR = YES; 296 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 297 | GCC_WARN_UNUSED_FUNCTION = YES; 298 | GCC_WARN_UNUSED_VARIABLE = YES; 299 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 300 | MTL_ENABLE_DEBUG_INFO = NO; 301 | SDKROOT = iphoneos; 302 | SWIFT_COMPILATION_MODE = wholemodule; 303 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 304 | VALIDATE_PRODUCT = YES; 305 | }; 306 | name = Release; 307 | }; 308 | E0884E7620D63CAF00ECD193 /* Debug */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 312 | CODE_SIGN_STYLE = Automatic; 313 | INFOPLIST_FILE = MeasuringPerformanceDemo/Info.plist; 314 | LD_RUNPATH_SEARCH_PATHS = ( 315 | "$(inherited)", 316 | "@executable_path/Frameworks", 317 | ); 318 | PRODUCT_BUNDLE_IDENTIFIER = com.shoheiyokoyama.MeasuringPerformanceDemo; 319 | PRODUCT_NAME = "$(TARGET_NAME)"; 320 | SWIFT_VERSION = 5.0; 321 | TARGETED_DEVICE_FAMILY = "1,2"; 322 | }; 323 | name = Debug; 324 | }; 325 | E0884E7720D63CAF00ECD193 /* Release */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 329 | CODE_SIGN_STYLE = Automatic; 330 | INFOPLIST_FILE = MeasuringPerformanceDemo/Info.plist; 331 | LD_RUNPATH_SEARCH_PATHS = ( 332 | "$(inherited)", 333 | "@executable_path/Frameworks", 334 | ); 335 | PRODUCT_BUNDLE_IDENTIFIER = com.shoheiyokoyama.MeasuringPerformanceDemo; 336 | PRODUCT_NAME = "$(TARGET_NAME)"; 337 | SWIFT_VERSION = 5.0; 338 | TARGETED_DEVICE_FAMILY = "1,2"; 339 | }; 340 | name = Release; 341 | }; 342 | /* End XCBuildConfiguration section */ 343 | 344 | /* Begin XCConfigurationList section */ 345 | E0884E5E20D63CAD00ECD193 /* Build configuration list for PBXProject "MeasuringPerformanceDemo" */ = { 346 | isa = XCConfigurationList; 347 | buildConfigurations = ( 348 | E0884E7320D63CAF00ECD193 /* Debug */, 349 | E0884E7420D63CAF00ECD193 /* Release */, 350 | ); 351 | defaultConfigurationIsVisible = 0; 352 | defaultConfigurationName = Release; 353 | }; 354 | E0884E7520D63CAF00ECD193 /* Build configuration list for PBXNativeTarget "MeasuringPerformanceDemo" */ = { 355 | isa = XCConfigurationList; 356 | buildConfigurations = ( 357 | E0884E7620D63CAF00ECD193 /* Debug */, 358 | E0884E7720D63CAF00ECD193 /* Release */, 359 | ); 360 | defaultConfigurationIsVisible = 0; 361 | defaultConfigurationName = Release; 362 | }; 363 | /* End XCConfigurationList section */ 364 | }; 365 | rootObject = E0884E5B20D63CAD00ECD193 /* Project object */; 366 | } 367 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo.xcodeproj/project.xcworkspace/xcuserdata/a14770.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shoheiyokoyama/DebuggingPerformance/d19d78480cfd250eb1bf0075b5f14da8961cd432/MeasuringPerformanceDemo.xcodeproj/project.xcworkspace/xcuserdata/a14770.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MeasuringPerformanceDemo.xcodeproj/xcuserdata/a14770.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo.xcodeproj/xcuserdata/a14770.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MeasuringPerformanceDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | MeasuringPerformanceDemo.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | 6 | var window: UIWindow? 7 | 8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 9 | return true 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/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 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/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 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/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 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/ImageDownloader.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | final class ImageDownloader { 4 | private var task: URLSessionDataTask? 5 | 6 | func download(url: URL, completionHandler: @escaping (_ image: UIImage, _ byteString: String) -> Void) { 7 | task = URLSession.shared.dataTask(with: url) { data, _, _ in 8 | guard let data = data, let image = UIImage(data: data) else { return } 9 | 10 | let formatter = ByteCountFormatter() 11 | formatter.allowedUnits = [.useKB] 12 | let byteString = formatter.string(fromByteCount: Int64(data.count)) 13 | completionHandler(image, byteString) 14 | } 15 | task?.resume() 16 | } 17 | 18 | func cancel() { 19 | task?.cancel() 20 | task = nil 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/ImageTableViewCell.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import os.signpost 3 | 4 | final class ImageTableViewCell: UITableViewCell { 5 | 6 | static let identifier = String(describing: ImageTableViewCell.self) 7 | 8 | @IBOutlet private weak var contentImageView: UIImageView! { 9 | didSet { 10 | contentImageView.clipsToBounds = true 11 | contentImageView.contentMode = .scaleAspectFill 12 | } 13 | } 14 | 15 | private let downloder = ImageDownloader() 16 | 17 | var contentImage: UIImage? { 18 | return contentImageView.image 19 | } 20 | 21 | override func prepareForReuse() { 22 | super.prepareForReuse() 23 | contentImageView.image = nil 24 | downloder.cancel() 25 | } 26 | 27 | func configure(with url: URL, at indexPath: IndexPath) { 28 | 29 | let signpostID = OSSignpostID(log: OSLog.fetchResource) 30 | os_signpost( 31 | .begin, 32 | log: OSLog.fetchResource, 33 | name: "download", 34 | signpostID: signpostID, 35 | "url: %s, indexPath.row: %d", url.absoluteString, indexPath.row 36 | ) 37 | 38 | downloder.download(url: url) { [weak self] image, byteString in 39 | DispatchQueue.main.async { 40 | self?.contentImageView.image = image 41 | } 42 | 43 | os_signpost( 44 | .end, 45 | log: OSLog.fetchResource, 46 | name: "download", 47 | signpostID: signpostID, 48 | "byte: %s", byteString 49 | ) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/ImageTableViewCell.xib: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/ImageURL.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | enum ImageURL { 4 | private static let base = "https://lorempixel.com" 5 | 6 | static func make() -> URL { 7 | let string = base 8 | + "/\(Int(UIScreen.main.bounds.width))" 9 | + "/\(Int.random(in: 2..<5))00/" 10 | return URL(string: string)! 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/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 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/OSLogExtension.swift: -------------------------------------------------------------------------------- 1 | import os.signpost 2 | import Foundation 3 | 4 | private let bundleID = Bundle.main.bundleIdentifier ?? "" 5 | 6 | extension OSLog { 7 | 8 | /// for measuring `OSSignpostType.event`. 9 | static let pointsOfInterest = OSLog(subsystem: bundleID, category: .pointsOfInterest) 10 | 11 | /// for measuring image download process. 12 | static let fetchResource = OSLog(subsystem: bundleID, category: "fetchResource") 13 | } 14 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/PhotoViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import os.signpost 3 | 4 | final class PhotoViewController: UIViewController { 5 | 6 | private static let nibName = String(describing: PhotoViewController.self) 7 | 8 | @IBOutlet private weak var imageView: UIImageView! { 9 | didSet { 10 | imageView.image = image 11 | } 12 | } 13 | 14 | private let image: UIImage 15 | 16 | init(image: UIImage) { 17 | self.image = image 18 | super.init(nibName: PhotoViewController.nibName, bundle: nil) 19 | } 20 | 21 | required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } 22 | 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | 26 | title = "Photo" 27 | os_signpost(.event, log: OSLog.pointsOfInterest, name: "PhotoViewController: viewDidLoad") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/PhotoViewController.xib: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /MeasuringPerformanceDemo/TableViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import os.signpost 3 | 4 | final class TableViewController: UITableViewController { 5 | 6 | override func viewDidLoad() { 7 | super.viewDidLoad() 8 | 9 | let nib = UINib(nibName: ImageTableViewCell.identifier, bundle: nil) 10 | tableView.register(nib, forCellReuseIdentifier: ImageTableViewCell.identifier) 11 | 12 | title = "Photo list" 13 | 14 | os_signpost(.event, log: OSLog.pointsOfInterest, name: "LisTableViewControllertVC: viewDidLoad") 15 | } 16 | 17 | // MARK: - Table view data source 18 | 19 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 20 | return 50 21 | } 22 | 23 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 24 | let cell = tableView.dequeueReusableCell(withIdentifier: ImageTableViewCell.identifier, for: indexPath) as! ImageTableViewCell 25 | cell.configure(with: ImageURL.make(), at: indexPath) 26 | return cell 27 | } 28 | 29 | // MARK: - Table view delegate 30 | 31 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 32 | return 200 33 | } 34 | 35 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 36 | guard let cell = tableView.cellForRow(at: indexPath) as? ImageTableViewCell else { return } 37 | guard let image = cell.contentImage else { return } 38 | 39 | let vc = PhotoViewController(image: image) 40 | navigationController?.pushViewController(vc, animated: true) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DebuggingPerformance 2 | 3 |

4 | 5 |

6 | 7 | Demo for debugging performance. 8 | 9 | ## Usage 10 | 11 | 1. Click `Product > Profile` or `Command + i`. 12 | 2. Choose a profiling template. 13 | 3. Start Recording. 14 | 15 | ## Reference 16 | 17 | - [Logging](https://developer.apple.com/documentation/os/logging) 18 | - [Measuring Performance Using Logging](https://developer.apple.com/videos/play/wwdc2018/405/) 19 | 20 | ## Requirements 21 | 22 | - Xcode 11.3 23 | 24 | ## Author 25 | 26 | Shohei Yokoyama 27 | 28 | - [GitHub](https://github.com/shoheiyokoyama) 29 | - [Facebook](https://www.facebook.com/shohei.yokoyama.96) 30 | - [Twitter](https://twitter.com/shoheiyokoyam) 31 | - Gmail: shohei.yok0602@gmail.com 32 | --------------------------------------------------------------------------------