├── .gitignore ├── .slather.yml ├── .swift-version ├── .travis.yml ├── CONTRIBUTING.md ├── Example └── MainThreadGuardDemo │ ├── MainThreadGuardDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── MainThreadGuardDemo.xcscheme │ ├── MainThreadGuardDemo.xcworkspace │ └── contents.xcworkspacedata │ ├── MainThreadGuardDemo │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Info.plist │ ├── Resources │ │ └── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ └── Sources │ │ ├── AppDelegate.swift │ │ └── ViewController.swift │ ├── Podfile │ └── Podfile.lock ├── LICENSE.md ├── MainThreadGuard.podspec ├── MainThreadGuard.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── MainThreadGuard-Mac.xcscheme │ └── MainThreadGuard-iOS.xcscheme ├── MainThreadGuard ├── Info-Mac.plist └── Info-iOS.plist ├── MainThreadGuardTests ├── Info-Mac.plist └── Info-iOS.plist ├── Playground-Mac.playground ├── Contents.swift ├── contents.xcplayground └── timeline.xctimeline ├── Playground-iOS.playground ├── Contents.swift ├── contents.xcplayground └── timeline.xctimeline ├── README.md ├── Screenshots └── Banner.png └── Sources └── MainThreadGuard.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | Icon 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | 10 | # Xcode 11 | # 12 | build/ 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata 22 | *.xccheckout 23 | *.moved-aside 24 | DerivedData 25 | *.hmap 26 | *.ipa 27 | *.xcuserstate 28 | 29 | # CocoaPods 30 | Pods 31 | 32 | # Carthage 33 | Carthage 34 | 35 | # SPM 36 | .build/ 37 | -------------------------------------------------------------------------------- /.slather.yml: -------------------------------------------------------------------------------- 1 | ci_service: travis_ci 2 | coverage_service: coveralls 3 | xcodeproj: MainThreadGuard.xcodeproj 4 | source_directory: Sources 5 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode7.3 2 | language: objective-c 3 | 4 | before_install: 5 | - brew update 6 | - if brew outdated | grep -qx carthage; then brew upgrade carthage; fi 7 | - travis_wait 35 carthage bootstrap --platform iOS,Mac 8 | 9 | script: 10 | - xcodebuild clean build -project MainThreadGuard.xcodeproj -scheme MainThreadGuard-iOS -sdk iphonesimulator 11 | - xcodebuild test -project MainThreadGuard.xcodeproj -scheme MainThreadGuard-iOS -sdk iphonesimulator 12 | - xcodebuild clean build -project MainThreadGuard.xcodeproj -scheme MainThreadGuard-Mac -sdk macosx 13 | - xcodebuild test -project MainThreadGuard.xcodeproj -scheme MainThreadGuard-Mac -sdk macosx 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | GitHub Issues is for reporting bugs, discussing features and general feedback in **MainThreadGuard**. Be sure to check our [documentation](http://cocoadocs.org/docsets/MainThreadGuard), [FAQ](https://github.com/onmyway133/MainThreadGuard/wiki/FAQ) and [past issues](https://github.com/onmyway133/MainThreadGuard/issues?state=closed) before opening any new issues. 2 | 3 | If you are posting about a crash in your application, a stack trace is helpful, but additional context, in the form of code and explanation, is necessary to be of any use. 4 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/MainThreadGuardDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B06C5EE9EB13093C3B4E6635 /* Pods_MainThreadGuardDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF36E29AD75384E35097DB72 /* Pods_MainThreadGuardDemo.framework */; }; 11 | D5C7F74E1C3BC9CE008CDDBA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5C7F74C1C3BC9CE008CDDBA /* LaunchScreen.storyboard */; }; 12 | D5C7F75B1C3BCA1E008CDDBA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D5C7F7571C3BCA1E008CDDBA /* Assets.xcassets */; }; 13 | D5C7F75C1C3BCA1E008CDDBA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C7F7591C3BCA1E008CDDBA /* AppDelegate.swift */; }; 14 | D5C7F75D1C3BCA1E008CDDBA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C7F75A1C3BCA1E008CDDBA /* ViewController.swift */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 03EBAA4635E67F759372643E /* Pods-MainThreadGuardDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MainThreadGuardDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-MainThreadGuardDemo/Pods-MainThreadGuardDemo.release.xcconfig"; sourceTree = ""; }; 19 | A65DEF7254DCE8699132D20D /* Pods-MainThreadGuardDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MainThreadGuardDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MainThreadGuardDemo/Pods-MainThreadGuardDemo.debug.xcconfig"; sourceTree = ""; }; 20 | D5C7F7401C3BC9CE008CDDBA /* MainThreadGuardDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MainThreadGuardDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | D5C7F74D1C3BC9CE008CDDBA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 22 | D5C7F74F1C3BC9CE008CDDBA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 23 | D5C7F7571C3BCA1E008CDDBA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | D5C7F7591C3BCA1E008CDDBA /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 25 | D5C7F75A1C3BCA1E008CDDBA /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 26 | FF36E29AD75384E35097DB72 /* Pods_MainThreadGuardDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MainThreadGuardDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | D5C7F73D1C3BC9CE008CDDBA /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | B06C5EE9EB13093C3B4E6635 /* Pods_MainThreadGuardDemo.framework in Frameworks */, 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 3B48EE171BA6AE0F093DA6F2 /* Frameworks */ = { 42 | isa = PBXGroup; 43 | children = ( 44 | FF36E29AD75384E35097DB72 /* Pods_MainThreadGuardDemo.framework */, 45 | ); 46 | name = Frameworks; 47 | sourceTree = ""; 48 | }; 49 | D5C7F7371C3BC9CE008CDDBA = { 50 | isa = PBXGroup; 51 | children = ( 52 | D5C7F7421C3BC9CE008CDDBA /* MainThreadGuardDemo */, 53 | D5C7F7411C3BC9CE008CDDBA /* Products */, 54 | F8C97405B612C6B745781F29 /* Pods */, 55 | 3B48EE171BA6AE0F093DA6F2 /* Frameworks */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | D5C7F7411C3BC9CE008CDDBA /* Products */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | D5C7F7401C3BC9CE008CDDBA /* MainThreadGuardDemo.app */, 63 | ); 64 | name = Products; 65 | sourceTree = ""; 66 | }; 67 | D5C7F7421C3BC9CE008CDDBA /* MainThreadGuardDemo */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | D5C7F7561C3BCA1E008CDDBA /* Resources */, 71 | D5C7F7581C3BCA1E008CDDBA /* Sources */, 72 | D5C7F7551C3BC9EA008CDDBA /* Supporting Files */, 73 | ); 74 | path = MainThreadGuardDemo; 75 | sourceTree = ""; 76 | }; 77 | D5C7F7551C3BC9EA008CDDBA /* Supporting Files */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | D5C7F74C1C3BC9CE008CDDBA /* LaunchScreen.storyboard */, 81 | D5C7F74F1C3BC9CE008CDDBA /* Info.plist */, 82 | ); 83 | name = "Supporting Files"; 84 | sourceTree = ""; 85 | }; 86 | D5C7F7561C3BCA1E008CDDBA /* Resources */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | D5C7F7571C3BCA1E008CDDBA /* Assets.xcassets */, 90 | ); 91 | path = Resources; 92 | sourceTree = ""; 93 | }; 94 | D5C7F7581C3BCA1E008CDDBA /* Sources */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | D5C7F7591C3BCA1E008CDDBA /* AppDelegate.swift */, 98 | D5C7F75A1C3BCA1E008CDDBA /* ViewController.swift */, 99 | ); 100 | path = Sources; 101 | sourceTree = ""; 102 | }; 103 | F8C97405B612C6B745781F29 /* Pods */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | A65DEF7254DCE8699132D20D /* Pods-MainThreadGuardDemo.debug.xcconfig */, 107 | 03EBAA4635E67F759372643E /* Pods-MainThreadGuardDemo.release.xcconfig */, 108 | ); 109 | name = Pods; 110 | sourceTree = ""; 111 | }; 112 | /* End PBXGroup section */ 113 | 114 | /* Begin PBXNativeTarget section */ 115 | D5C7F73F1C3BC9CE008CDDBA /* MainThreadGuardDemo */ = { 116 | isa = PBXNativeTarget; 117 | buildConfigurationList = D5C7F7521C3BC9CE008CDDBA /* Build configuration list for PBXNativeTarget "MainThreadGuardDemo" */; 118 | buildPhases = ( 119 | B3E52B635DEC320D1D8DC06C /* [CP] Check Pods Manifest.lock */, 120 | D5C7F73C1C3BC9CE008CDDBA /* Sources */, 121 | D5C7F73D1C3BC9CE008CDDBA /* Frameworks */, 122 | D5C7F73E1C3BC9CE008CDDBA /* Resources */, 123 | 607E19396F4FAA91162EDF8C /* [CP] Embed Pods Frameworks */, 124 | 6C412B76FC707B84C3F83F77 /* [CP] Copy Pods Resources */, 125 | ); 126 | buildRules = ( 127 | ); 128 | dependencies = ( 129 | ); 130 | name = MainThreadGuardDemo; 131 | productName = MainThreadGuardDemo; 132 | productReference = D5C7F7401C3BC9CE008CDDBA /* MainThreadGuardDemo.app */; 133 | productType = "com.apple.product-type.application"; 134 | }; 135 | /* End PBXNativeTarget section */ 136 | 137 | /* Begin PBXProject section */ 138 | D5C7F7381C3BC9CE008CDDBA /* Project object */ = { 139 | isa = PBXProject; 140 | attributes = { 141 | LastSwiftUpdateCheck = 0720; 142 | LastUpgradeCheck = 0720; 143 | ORGANIZATIONNAME = "Hyper Interaktiv AS"; 144 | TargetAttributes = { 145 | D5C7F73F1C3BC9CE008CDDBA = { 146 | CreatedOnToolsVersion = 7.2; 147 | LastSwiftMigration = 0810; 148 | }; 149 | }; 150 | }; 151 | buildConfigurationList = D5C7F73B1C3BC9CE008CDDBA /* Build configuration list for PBXProject "MainThreadGuardDemo" */; 152 | compatibilityVersion = "Xcode 3.2"; 153 | developmentRegion = English; 154 | hasScannedForEncodings = 0; 155 | knownRegions = ( 156 | en, 157 | Base, 158 | ); 159 | mainGroup = D5C7F7371C3BC9CE008CDDBA; 160 | productRefGroup = D5C7F7411C3BC9CE008CDDBA /* Products */; 161 | projectDirPath = ""; 162 | projectRoot = ""; 163 | targets = ( 164 | D5C7F73F1C3BC9CE008CDDBA /* MainThreadGuardDemo */, 165 | ); 166 | }; 167 | /* End PBXProject section */ 168 | 169 | /* Begin PBXResourcesBuildPhase section */ 170 | D5C7F73E1C3BC9CE008CDDBA /* Resources */ = { 171 | isa = PBXResourcesBuildPhase; 172 | buildActionMask = 2147483647; 173 | files = ( 174 | D5C7F75B1C3BCA1E008CDDBA /* Assets.xcassets in Resources */, 175 | D5C7F74E1C3BC9CE008CDDBA /* LaunchScreen.storyboard in Resources */, 176 | ); 177 | runOnlyForDeploymentPostprocessing = 0; 178 | }; 179 | /* End PBXResourcesBuildPhase section */ 180 | 181 | /* Begin PBXShellScriptBuildPhase section */ 182 | 607E19396F4FAA91162EDF8C /* [CP] Embed Pods Frameworks */ = { 183 | isa = PBXShellScriptBuildPhase; 184 | buildActionMask = 2147483647; 185 | files = ( 186 | ); 187 | inputPaths = ( 188 | ); 189 | name = "[CP] Embed Pods Frameworks"; 190 | outputPaths = ( 191 | ); 192 | runOnlyForDeploymentPostprocessing = 0; 193 | shellPath = /bin/sh; 194 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MainThreadGuardDemo/Pods-MainThreadGuardDemo-frameworks.sh\"\n"; 195 | showEnvVarsInLog = 0; 196 | }; 197 | 6C412B76FC707B84C3F83F77 /* [CP] Copy Pods Resources */ = { 198 | isa = PBXShellScriptBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | ); 202 | inputPaths = ( 203 | ); 204 | name = "[CP] Copy Pods Resources"; 205 | outputPaths = ( 206 | ); 207 | runOnlyForDeploymentPostprocessing = 0; 208 | shellPath = /bin/sh; 209 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MainThreadGuardDemo/Pods-MainThreadGuardDemo-resources.sh\"\n"; 210 | showEnvVarsInLog = 0; 211 | }; 212 | B3E52B635DEC320D1D8DC06C /* [CP] Check Pods Manifest.lock */ = { 213 | isa = PBXShellScriptBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | ); 217 | inputPaths = ( 218 | ); 219 | name = "[CP] Check Pods Manifest.lock"; 220 | outputPaths = ( 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | shellPath = /bin/sh; 224 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 225 | showEnvVarsInLog = 0; 226 | }; 227 | /* End PBXShellScriptBuildPhase section */ 228 | 229 | /* Begin PBXSourcesBuildPhase section */ 230 | D5C7F73C1C3BC9CE008CDDBA /* Sources */ = { 231 | isa = PBXSourcesBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | D5C7F75D1C3BCA1E008CDDBA /* ViewController.swift in Sources */, 235 | D5C7F75C1C3BCA1E008CDDBA /* AppDelegate.swift in Sources */, 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | }; 239 | /* End PBXSourcesBuildPhase section */ 240 | 241 | /* Begin PBXVariantGroup section */ 242 | D5C7F74C1C3BC9CE008CDDBA /* LaunchScreen.storyboard */ = { 243 | isa = PBXVariantGroup; 244 | children = ( 245 | D5C7F74D1C3BC9CE008CDDBA /* Base */, 246 | ); 247 | name = LaunchScreen.storyboard; 248 | sourceTree = ""; 249 | }; 250 | /* End PBXVariantGroup section */ 251 | 252 | /* Begin XCBuildConfiguration section */ 253 | D5C7F7501C3BC9CE008CDDBA /* Debug */ = { 254 | isa = XCBuildConfiguration; 255 | buildSettings = { 256 | ALWAYS_SEARCH_USER_PATHS = NO; 257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 258 | CLANG_CXX_LIBRARY = "libc++"; 259 | CLANG_ENABLE_MODULES = YES; 260 | CLANG_ENABLE_OBJC_ARC = YES; 261 | CLANG_WARN_BOOL_CONVERSION = YES; 262 | CLANG_WARN_CONSTANT_CONVERSION = YES; 263 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 264 | CLANG_WARN_EMPTY_BODY = YES; 265 | CLANG_WARN_ENUM_CONVERSION = YES; 266 | CLANG_WARN_INT_CONVERSION = YES; 267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 268 | CLANG_WARN_UNREACHABLE_CODE = YES; 269 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 270 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 271 | COPY_PHASE_STRIP = NO; 272 | DEBUG_INFORMATION_FORMAT = dwarf; 273 | ENABLE_STRICT_OBJC_MSGSEND = YES; 274 | ENABLE_TESTABILITY = YES; 275 | GCC_C_LANGUAGE_STANDARD = gnu99; 276 | GCC_DYNAMIC_NO_PIC = NO; 277 | GCC_NO_COMMON_BLOCKS = YES; 278 | GCC_OPTIMIZATION_LEVEL = 0; 279 | GCC_PREPROCESSOR_DEFINITIONS = ( 280 | "DEBUG=1", 281 | "$(inherited)", 282 | ); 283 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 284 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 285 | GCC_WARN_UNDECLARED_SELECTOR = YES; 286 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 287 | GCC_WARN_UNUSED_FUNCTION = YES; 288 | GCC_WARN_UNUSED_VARIABLE = YES; 289 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 290 | MTL_ENABLE_DEBUG_INFO = YES; 291 | ONLY_ACTIVE_ARCH = YES; 292 | SDKROOT = iphoneos; 293 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 294 | }; 295 | name = Debug; 296 | }; 297 | D5C7F7511C3BC9CE008CDDBA /* Release */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ALWAYS_SEARCH_USER_PATHS = NO; 301 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 302 | CLANG_CXX_LIBRARY = "libc++"; 303 | CLANG_ENABLE_MODULES = YES; 304 | CLANG_ENABLE_OBJC_ARC = YES; 305 | CLANG_WARN_BOOL_CONVERSION = YES; 306 | CLANG_WARN_CONSTANT_CONVERSION = YES; 307 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 308 | CLANG_WARN_EMPTY_BODY = YES; 309 | CLANG_WARN_ENUM_CONVERSION = YES; 310 | CLANG_WARN_INT_CONVERSION = YES; 311 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 312 | CLANG_WARN_UNREACHABLE_CODE = YES; 313 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 314 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 315 | COPY_PHASE_STRIP = NO; 316 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 317 | ENABLE_NS_ASSERTIONS = NO; 318 | ENABLE_STRICT_OBJC_MSGSEND = YES; 319 | GCC_C_LANGUAGE_STANDARD = gnu99; 320 | GCC_NO_COMMON_BLOCKS = YES; 321 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 322 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 323 | GCC_WARN_UNDECLARED_SELECTOR = YES; 324 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 325 | GCC_WARN_UNUSED_FUNCTION = YES; 326 | GCC_WARN_UNUSED_VARIABLE = YES; 327 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 328 | MTL_ENABLE_DEBUG_INFO = NO; 329 | SDKROOT = iphoneos; 330 | VALIDATE_PRODUCT = YES; 331 | }; 332 | name = Release; 333 | }; 334 | D5C7F7531C3BC9CE008CDDBA /* Debug */ = { 335 | isa = XCBuildConfiguration; 336 | baseConfigurationReference = A65DEF7254DCE8699132D20D /* Pods-MainThreadGuardDemo.debug.xcconfig */; 337 | buildSettings = { 338 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 339 | INFOPLIST_FILE = MainThreadGuardDemo/Info.plist; 340 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 341 | PRODUCT_BUNDLE_IDENTIFIER = com.fantageek.MainThreadGuard.MainThreadGuardDemo; 342 | PRODUCT_NAME = "$(TARGET_NAME)"; 343 | SWIFT_VERSION = 3.0; 344 | }; 345 | name = Debug; 346 | }; 347 | D5C7F7541C3BC9CE008CDDBA /* Release */ = { 348 | isa = XCBuildConfiguration; 349 | baseConfigurationReference = 03EBAA4635E67F759372643E /* Pods-MainThreadGuardDemo.release.xcconfig */; 350 | buildSettings = { 351 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 352 | INFOPLIST_FILE = MainThreadGuardDemo/Info.plist; 353 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 354 | PRODUCT_BUNDLE_IDENTIFIER = com.fantageek.MainThreadGuard.MainThreadGuardDemo; 355 | PRODUCT_NAME = "$(TARGET_NAME)"; 356 | SWIFT_VERSION = 3.0; 357 | }; 358 | name = Release; 359 | }; 360 | /* End XCBuildConfiguration section */ 361 | 362 | /* Begin XCConfigurationList section */ 363 | D5C7F73B1C3BC9CE008CDDBA /* Build configuration list for PBXProject "MainThreadGuardDemo" */ = { 364 | isa = XCConfigurationList; 365 | buildConfigurations = ( 366 | D5C7F7501C3BC9CE008CDDBA /* Debug */, 367 | D5C7F7511C3BC9CE008CDDBA /* Release */, 368 | ); 369 | defaultConfigurationIsVisible = 0; 370 | defaultConfigurationName = Release; 371 | }; 372 | D5C7F7521C3BC9CE008CDDBA /* Build configuration list for PBXNativeTarget "MainThreadGuardDemo" */ = { 373 | isa = XCConfigurationList; 374 | buildConfigurations = ( 375 | D5C7F7531C3BC9CE008CDDBA /* Debug */, 376 | D5C7F7541C3BC9CE008CDDBA /* Release */, 377 | ); 378 | defaultConfigurationIsVisible = 0; 379 | defaultConfigurationName = Release; 380 | }; 381 | /* End XCConfigurationList section */ 382 | }; 383 | rootObject = D5C7F7381C3BC9CE008CDDBA /* Project object */; 384 | } 385 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/MainThreadGuardDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/MainThreadGuardDemo.xcodeproj/xcshareddata/xcschemes/MainThreadGuardDemo.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 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/MainThreadGuardDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/MainThreadGuardDemo/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 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/MainThreadGuardDemo/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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/MainThreadGuardDemo/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/MainThreadGuardDemo/Sources/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import MainThreadGuard 3 | 4 | @UIApplicationMain 5 | class AppDelegate: UIResponder, UIApplicationDelegate { 6 | 7 | var window: UIWindow? 8 | 9 | lazy var navigationController: UINavigationController = { [unowned self] in 10 | let controller = UINavigationController(rootViewController: self.viewController) 11 | return controller 12 | }() 13 | 14 | lazy var viewController: ViewController = { 15 | let controller = ViewController() 16 | return controller 17 | }() 18 | 19 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 20 | window = UIWindow(frame: UIScreen.main.bounds) 21 | window?.rootViewController = navigationController 22 | window?.makeKeyAndVisible() 23 | 24 | Guard.setup() 25 | 26 | return true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/MainThreadGuardDemo/Sources/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class ViewController: UIViewController { 4 | 5 | override func viewDidLoad() { 6 | super.viewDidLoad() 7 | view.backgroundColor = UIColor.white 8 | 9 | let label = UILabel() 10 | view.addSubview(label) 11 | 12 | DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async { 13 | label.text = "Setting text on background thread" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | platform :ios, '8.0' 4 | 5 | target 'MainThreadGuardDemo' do 6 | pod 'MainThreadGuard', path: '../../', configurations: 'Debug' 7 | end 8 | 9 | -------------------------------------------------------------------------------- /Example/MainThreadGuardDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - MainThreadGuard (1.0.0) 3 | 4 | DEPENDENCIES: 5 | - MainThreadGuard (from `../../`) 6 | 7 | EXTERNAL SOURCES: 8 | MainThreadGuard: 9 | :path: "../../" 10 | 11 | SPEC CHECKSUMS: 12 | MainThreadGuard: 39f8c507db14c547f97b6ad9087dfc879e298466 13 | 14 | PODFILE CHECKSUM: f809bf658182cc3650e2f46ed7216e38dfc95aa1 15 | 16 | COCOAPODS: 1.1.1 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Licensed under the **MIT** license 2 | 3 | > Copyright (c) 2015 Khoa Pham 4 | > 5 | > Permission is hereby granted, free of charge, to any person obtaining 6 | > a copy of this software and associated documentation files (the 7 | > "Software"), to deal in the Software without restriction, including 8 | > without limitation the rights to use, copy, modify, merge, publish, 9 | > distribute, sublicense, and/or sell copies of the Software, and to 10 | > permit persons to whom the Software is furnished to do so, subject to 11 | > the following conditions: 12 | > 13 | > The above copyright notice and this permission notice shall be 14 | > included in all copies or substantial portions of the Software. 15 | > 16 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /MainThreadGuard.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "MainThreadGuard" 3 | s.summary = "Tracking UIKit access on main thread" 4 | s.version = "2.1.0" 5 | s.homepage = "https://github.com/onmyway133/MainThreadGuard" 6 | s.license = 'MIT' 7 | s.author = { "Khoa Pham" => "onmyway133@gmail.com" } 8 | s.source = { 9 | :git => "https://github.com/onmyway133/MainThreadGuard.git", 10 | :tag => s.version.to_s 11 | } 12 | s.social_media_url = 'https://twitter.com/onmyway133' 13 | 14 | s.ios.deployment_target = '8.0' 15 | s.tvos.deployment_target = '9.2' 16 | 17 | s.requires_arc = true 18 | s.source_files = 'Sources/**/*' 19 | 20 | s.ios.frameworks = 'UIKit', 'Foundation' 21 | 22 | s.pod_target_xcconfig = { 'SWIFT_VERSION' => '3.0' } 23 | end 24 | -------------------------------------------------------------------------------- /MainThreadGuard.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D226B7471CD48E4700EFDFE3 /* MainThreadGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D226B7461CD48E4700EFDFE3 /* MainThreadGuard.swift */; }; 11 | D226B7481CD48E4700EFDFE3 /* MainThreadGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D226B7461CD48E4700EFDFE3 /* MainThreadGuard.swift */; }; 12 | D5B2E8AA1C3A780C00C0327D /* MainThreadGuard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5B2E89F1C3A780C00C0327D /* MainThreadGuard.framework */; }; 13 | D5C6294A1C3A7FAA007F7B7C /* MainThreadGuard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5C629401C3A7FAA007F7B7C /* MainThreadGuard.framework */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXContainerItemProxy section */ 17 | D5B2E8AB1C3A780C00C0327D /* PBXContainerItemProxy */ = { 18 | isa = PBXContainerItemProxy; 19 | containerPortal = D5B2E8961C3A780C00C0327D /* Project object */; 20 | proxyType = 1; 21 | remoteGlobalIDString = D5B2E89E1C3A780C00C0327D; 22 | remoteInfo = MainThreadGuard; 23 | }; 24 | D5C6294B1C3A7FAA007F7B7C /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = D5B2E8961C3A780C00C0327D /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = D5C6293F1C3A7FAA007F7B7C; 29 | remoteInfo = "MainThreadGuard-Mac"; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | D226B7461CD48E4700EFDFE3 /* MainThreadGuard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainThreadGuard.swift; sourceTree = ""; }; 35 | D500FD111C3AABED00782D78 /* Playground-iOS.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Playground-iOS.playground"; sourceTree = ""; }; 36 | D500FD121C3AAC8E00782D78 /* Playground-Mac.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Playground-Mac.playground"; sourceTree = ""; }; 37 | D5B2E89F1C3A780C00C0327D /* MainThreadGuard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MainThreadGuard.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | D5B2E8A91C3A780C00C0327D /* MainThreadGuard-iOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MainThreadGuard-iOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | D5C629401C3A7FAA007F7B7C /* MainThreadGuard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MainThreadGuard.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | D5C629491C3A7FAA007F7B7C /* MainThreadGuard-Mac-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MainThreadGuard-Mac-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | D5C6298B1C3A8BBD007F7B7C /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 42 | D5C6298C1C3A8BBD007F7B7C /* Info-Mac.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Mac.plist"; sourceTree = ""; }; 43 | D5C629901C3A8BDA007F7B7C /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 44 | D5C629911C3A8BDA007F7B7C /* Info-Mac.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Mac.plist"; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | D5B2E89B1C3A780C00C0327D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | D5B2E8A61C3A780C00C0327D /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | D5B2E8AA1C3A780C00C0327D /* MainThreadGuard.framework in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | D5C6293C1C3A7FAA007F7B7C /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | D5C629461C3A7FAA007F7B7C /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | D5C6294A1C3A7FAA007F7B7C /* MainThreadGuard.framework in Frameworks */, 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXFrameworksBuildPhase section */ 79 | 80 | /* Begin PBXGroup section */ 81 | D5B2E8951C3A780C00C0327D = { 82 | isa = PBXGroup; 83 | children = ( 84 | D500FD111C3AABED00782D78 /* Playground-iOS.playground */, 85 | D500FD121C3AAC8E00782D78 /* Playground-Mac.playground */, 86 | D5C629691C3A809D007F7B7C /* Sources */, 87 | D5C6295C1C3A800E007F7B7C /* MainThreadGuard */, 88 | D5C6298F1C3A8BDA007F7B7C /* MainThreadGuardTests */, 89 | D5B2E8A01C3A780C00C0327D /* Products */, 90 | ); 91 | sourceTree = ""; 92 | }; 93 | D5B2E8A01C3A780C00C0327D /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | D5B2E89F1C3A780C00C0327D /* MainThreadGuard.framework */, 97 | D5B2E8A91C3A780C00C0327D /* MainThreadGuard-iOS-Tests.xctest */, 98 | D5C629401C3A7FAA007F7B7C /* MainThreadGuard.framework */, 99 | D5C629491C3A7FAA007F7B7C /* MainThreadGuard-Mac-Tests.xctest */, 100 | ); 101 | name = Products; 102 | sourceTree = ""; 103 | }; 104 | D5C6295C1C3A800E007F7B7C /* MainThreadGuard */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | D5C6298B1C3A8BBD007F7B7C /* Info-iOS.plist */, 108 | D5C6298C1C3A8BBD007F7B7C /* Info-Mac.plist */, 109 | ); 110 | path = MainThreadGuard; 111 | sourceTree = ""; 112 | }; 113 | D5C629691C3A809D007F7B7C /* Sources */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | D226B7461CD48E4700EFDFE3 /* MainThreadGuard.swift */, 117 | ); 118 | path = Sources; 119 | sourceTree = ""; 120 | }; 121 | D5C6298F1C3A8BDA007F7B7C /* MainThreadGuardTests */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | D5C629901C3A8BDA007F7B7C /* Info-iOS.plist */, 125 | D5C629911C3A8BDA007F7B7C /* Info-Mac.plist */, 126 | ); 127 | path = MainThreadGuardTests; 128 | sourceTree = ""; 129 | }; 130 | /* End PBXGroup section */ 131 | 132 | /* Begin PBXHeadersBuildPhase section */ 133 | D5B2E89C1C3A780C00C0327D /* Headers */ = { 134 | isa = PBXHeadersBuildPhase; 135 | buildActionMask = 2147483647; 136 | files = ( 137 | ); 138 | runOnlyForDeploymentPostprocessing = 0; 139 | }; 140 | D5C6293D1C3A7FAA007F7B7C /* Headers */ = { 141 | isa = PBXHeadersBuildPhase; 142 | buildActionMask = 2147483647; 143 | files = ( 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXHeadersBuildPhase section */ 148 | 149 | /* Begin PBXNativeTarget section */ 150 | D5B2E89E1C3A780C00C0327D /* MainThreadGuard-iOS */ = { 151 | isa = PBXNativeTarget; 152 | buildConfigurationList = D5B2E8B31C3A780C00C0327D /* Build configuration list for PBXNativeTarget "MainThreadGuard-iOS" */; 153 | buildPhases = ( 154 | D5B2E89A1C3A780C00C0327D /* Sources */, 155 | D5B2E89B1C3A780C00C0327D /* Frameworks */, 156 | D5B2E89C1C3A780C00C0327D /* Headers */, 157 | D5B2E89D1C3A780C00C0327D /* Resources */, 158 | ); 159 | buildRules = ( 160 | ); 161 | dependencies = ( 162 | ); 163 | name = "MainThreadGuard-iOS"; 164 | productName = MainThreadGuard; 165 | productReference = D5B2E89F1C3A780C00C0327D /* MainThreadGuard.framework */; 166 | productType = "com.apple.product-type.framework"; 167 | }; 168 | D5B2E8A81C3A780C00C0327D /* MainThreadGuard-iOS-Tests */ = { 169 | isa = PBXNativeTarget; 170 | buildConfigurationList = D5B2E8B61C3A780C00C0327D /* Build configuration list for PBXNativeTarget "MainThreadGuard-iOS-Tests" */; 171 | buildPhases = ( 172 | D5B2E8A51C3A780C00C0327D /* Sources */, 173 | D5B2E8A61C3A780C00C0327D /* Frameworks */, 174 | D5B2E8A71C3A780C00C0327D /* Resources */, 175 | D5C629731C3A86E3007F7B7C /* Copy frameworks with Carthage */, 176 | ); 177 | buildRules = ( 178 | ); 179 | dependencies = ( 180 | D5B2E8AC1C3A780C00C0327D /* PBXTargetDependency */, 181 | ); 182 | name = "MainThreadGuard-iOS-Tests"; 183 | productName = MainThreadGuardTests; 184 | productReference = D5B2E8A91C3A780C00C0327D /* MainThreadGuard-iOS-Tests.xctest */; 185 | productType = "com.apple.product-type.bundle.unit-test"; 186 | }; 187 | D5C6293F1C3A7FAA007F7B7C /* MainThreadGuard-Mac */ = { 188 | isa = PBXNativeTarget; 189 | buildConfigurationList = D5C629511C3A7FAA007F7B7C /* Build configuration list for PBXNativeTarget "MainThreadGuard-Mac" */; 190 | buildPhases = ( 191 | D5C6293B1C3A7FAA007F7B7C /* Sources */, 192 | D5C6293C1C3A7FAA007F7B7C /* Frameworks */, 193 | D5C6293D1C3A7FAA007F7B7C /* Headers */, 194 | D5C6293E1C3A7FAA007F7B7C /* Resources */, 195 | ); 196 | buildRules = ( 197 | ); 198 | dependencies = ( 199 | ); 200 | name = "MainThreadGuard-Mac"; 201 | productName = "MainThreadGuard-Mac"; 202 | productReference = D5C629401C3A7FAA007F7B7C /* MainThreadGuard.framework */; 203 | productType = "com.apple.product-type.framework"; 204 | }; 205 | D5C629481C3A7FAA007F7B7C /* MainThreadGuard-Mac-Tests */ = { 206 | isa = PBXNativeTarget; 207 | buildConfigurationList = D5C629541C3A7FAA007F7B7C /* Build configuration list for PBXNativeTarget "MainThreadGuard-Mac-Tests" */; 208 | buildPhases = ( 209 | D5C629451C3A7FAA007F7B7C /* Sources */, 210 | D5C629461C3A7FAA007F7B7C /* Frameworks */, 211 | D5C629471C3A7FAA007F7B7C /* Resources */, 212 | D5C629741C3A8717007F7B7C /* Copy frameworks with Carthage */, 213 | ); 214 | buildRules = ( 215 | ); 216 | dependencies = ( 217 | D5C6294C1C3A7FAA007F7B7C /* PBXTargetDependency */, 218 | ); 219 | name = "MainThreadGuard-Mac-Tests"; 220 | productName = "MainThreadGuard-MacTests"; 221 | productReference = D5C629491C3A7FAA007F7B7C /* MainThreadGuard-Mac-Tests.xctest */; 222 | productType = "com.apple.product-type.bundle.unit-test"; 223 | }; 224 | /* End PBXNativeTarget section */ 225 | 226 | /* Begin PBXProject section */ 227 | D5B2E8961C3A780C00C0327D /* Project object */ = { 228 | isa = PBXProject; 229 | attributes = { 230 | LastSwiftUpdateCheck = 0730; 231 | LastUpgradeCheck = 0720; 232 | ORGANIZATIONNAME = Fantageek; 233 | TargetAttributes = { 234 | D5B2E89E1C3A780C00C0327D = { 235 | CreatedOnToolsVersion = 7.2; 236 | LastSwiftMigration = 0810; 237 | }; 238 | D5B2E8A81C3A780C00C0327D = { 239 | CreatedOnToolsVersion = 7.2; 240 | LastSwiftMigration = 0810; 241 | }; 242 | D5C6293F1C3A7FAA007F7B7C = { 243 | CreatedOnToolsVersion = 7.2; 244 | }; 245 | D5C629481C3A7FAA007F7B7C = { 246 | CreatedOnToolsVersion = 7.2; 247 | }; 248 | }; 249 | }; 250 | buildConfigurationList = D5B2E8991C3A780C00C0327D /* Build configuration list for PBXProject "MainThreadGuard" */; 251 | compatibilityVersion = "Xcode 3.2"; 252 | developmentRegion = English; 253 | hasScannedForEncodings = 0; 254 | knownRegions = ( 255 | en, 256 | ); 257 | mainGroup = D5B2E8951C3A780C00C0327D; 258 | productRefGroup = D5B2E8A01C3A780C00C0327D /* Products */; 259 | projectDirPath = ""; 260 | projectRoot = ""; 261 | targets = ( 262 | D5B2E89E1C3A780C00C0327D /* MainThreadGuard-iOS */, 263 | D5C6293F1C3A7FAA007F7B7C /* MainThreadGuard-Mac */, 264 | D5B2E8A81C3A780C00C0327D /* MainThreadGuard-iOS-Tests */, 265 | D5C629481C3A7FAA007F7B7C /* MainThreadGuard-Mac-Tests */, 266 | ); 267 | }; 268 | /* End PBXProject section */ 269 | 270 | /* Begin PBXResourcesBuildPhase section */ 271 | D5B2E89D1C3A780C00C0327D /* Resources */ = { 272 | isa = PBXResourcesBuildPhase; 273 | buildActionMask = 2147483647; 274 | files = ( 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | }; 278 | D5B2E8A71C3A780C00C0327D /* Resources */ = { 279 | isa = PBXResourcesBuildPhase; 280 | buildActionMask = 2147483647; 281 | files = ( 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | D5C6293E1C3A7FAA007F7B7C /* Resources */ = { 286 | isa = PBXResourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | D5C629471C3A7FAA007F7B7C /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | }; 299 | /* End PBXResourcesBuildPhase section */ 300 | 301 | /* Begin PBXShellScriptBuildPhase section */ 302 | D5C629731C3A86E3007F7B7C /* Copy frameworks with Carthage */ = { 303 | isa = PBXShellScriptBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | ); 307 | inputPaths = ( 308 | ); 309 | name = "Copy frameworks with Carthage"; 310 | outputPaths = ( 311 | ); 312 | runOnlyForDeploymentPostprocessing = 0; 313 | shellPath = /bin/sh; 314 | shellScript = "/usr/local/bin/carthage copy-frameworks"; 315 | }; 316 | D5C629741C3A8717007F7B7C /* Copy frameworks with Carthage */ = { 317 | isa = PBXShellScriptBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | ); 321 | inputPaths = ( 322 | ); 323 | name = "Copy frameworks with Carthage"; 324 | outputPaths = ( 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | shellPath = /bin/sh; 328 | shellScript = "/usr/local/bin/carthage copy-frameworks"; 329 | }; 330 | /* End PBXShellScriptBuildPhase section */ 331 | 332 | /* Begin PBXSourcesBuildPhase section */ 333 | D5B2E89A1C3A780C00C0327D /* Sources */ = { 334 | isa = PBXSourcesBuildPhase; 335 | buildActionMask = 2147483647; 336 | files = ( 337 | D226B7471CD48E4700EFDFE3 /* MainThreadGuard.swift in Sources */, 338 | ); 339 | runOnlyForDeploymentPostprocessing = 0; 340 | }; 341 | D5B2E8A51C3A780C00C0327D /* Sources */ = { 342 | isa = PBXSourcesBuildPhase; 343 | buildActionMask = 2147483647; 344 | files = ( 345 | ); 346 | runOnlyForDeploymentPostprocessing = 0; 347 | }; 348 | D5C6293B1C3A7FAA007F7B7C /* Sources */ = { 349 | isa = PBXSourcesBuildPhase; 350 | buildActionMask = 2147483647; 351 | files = ( 352 | D226B7481CD48E4700EFDFE3 /* MainThreadGuard.swift in Sources */, 353 | ); 354 | runOnlyForDeploymentPostprocessing = 0; 355 | }; 356 | D5C629451C3A7FAA007F7B7C /* Sources */ = { 357 | isa = PBXSourcesBuildPhase; 358 | buildActionMask = 2147483647; 359 | files = ( 360 | ); 361 | runOnlyForDeploymentPostprocessing = 0; 362 | }; 363 | /* End PBXSourcesBuildPhase section */ 364 | 365 | /* Begin PBXTargetDependency section */ 366 | D5B2E8AC1C3A780C00C0327D /* PBXTargetDependency */ = { 367 | isa = PBXTargetDependency; 368 | target = D5B2E89E1C3A780C00C0327D /* MainThreadGuard-iOS */; 369 | targetProxy = D5B2E8AB1C3A780C00C0327D /* PBXContainerItemProxy */; 370 | }; 371 | D5C6294C1C3A7FAA007F7B7C /* PBXTargetDependency */ = { 372 | isa = PBXTargetDependency; 373 | target = D5C6293F1C3A7FAA007F7B7C /* MainThreadGuard-Mac */; 374 | targetProxy = D5C6294B1C3A7FAA007F7B7C /* PBXContainerItemProxy */; 375 | }; 376 | /* End PBXTargetDependency section */ 377 | 378 | /* Begin XCBuildConfiguration section */ 379 | D5B2E8B11C3A780C00C0327D /* Debug */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | ALWAYS_SEARCH_USER_PATHS = NO; 383 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 384 | CLANG_CXX_LIBRARY = "libc++"; 385 | CLANG_ENABLE_MODULES = YES; 386 | CLANG_ENABLE_OBJC_ARC = YES; 387 | CLANG_WARN_BOOL_CONVERSION = YES; 388 | CLANG_WARN_CONSTANT_CONVERSION = YES; 389 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 390 | CLANG_WARN_EMPTY_BODY = YES; 391 | CLANG_WARN_ENUM_CONVERSION = YES; 392 | CLANG_WARN_INT_CONVERSION = YES; 393 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 394 | CLANG_WARN_UNREACHABLE_CODE = YES; 395 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 396 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 397 | COPY_PHASE_STRIP = NO; 398 | CURRENT_PROJECT_VERSION = 1; 399 | DEBUG_INFORMATION_FORMAT = dwarf; 400 | ENABLE_STRICT_OBJC_MSGSEND = YES; 401 | ENABLE_TESTABILITY = YES; 402 | GCC_C_LANGUAGE_STANDARD = gnu99; 403 | GCC_DYNAMIC_NO_PIC = NO; 404 | GCC_NO_COMMON_BLOCKS = YES; 405 | GCC_OPTIMIZATION_LEVEL = 0; 406 | GCC_PREPROCESSOR_DEFINITIONS = ( 407 | "DEBUG=1", 408 | "$(inherited)", 409 | ); 410 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 411 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 412 | GCC_WARN_UNDECLARED_SELECTOR = YES; 413 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 414 | GCC_WARN_UNUSED_FUNCTION = YES; 415 | GCC_WARN_UNUSED_VARIABLE = YES; 416 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 417 | MTL_ENABLE_DEBUG_INFO = YES; 418 | ONLY_ACTIVE_ARCH = YES; 419 | SDKROOT = iphoneos; 420 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 421 | TARGETED_DEVICE_FAMILY = "1,2"; 422 | VERSIONING_SYSTEM = "apple-generic"; 423 | VERSION_INFO_PREFIX = ""; 424 | }; 425 | name = Debug; 426 | }; 427 | D5B2E8B21C3A780C00C0327D /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ALWAYS_SEARCH_USER_PATHS = NO; 431 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 432 | CLANG_CXX_LIBRARY = "libc++"; 433 | CLANG_ENABLE_MODULES = YES; 434 | CLANG_ENABLE_OBJC_ARC = YES; 435 | CLANG_WARN_BOOL_CONVERSION = YES; 436 | CLANG_WARN_CONSTANT_CONVERSION = YES; 437 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 438 | CLANG_WARN_EMPTY_BODY = YES; 439 | CLANG_WARN_ENUM_CONVERSION = YES; 440 | CLANG_WARN_INT_CONVERSION = YES; 441 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 442 | CLANG_WARN_UNREACHABLE_CODE = YES; 443 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 444 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 445 | COPY_PHASE_STRIP = NO; 446 | CURRENT_PROJECT_VERSION = 1; 447 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 448 | ENABLE_NS_ASSERTIONS = NO; 449 | ENABLE_STRICT_OBJC_MSGSEND = YES; 450 | GCC_C_LANGUAGE_STANDARD = gnu99; 451 | GCC_NO_COMMON_BLOCKS = YES; 452 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 453 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 454 | GCC_WARN_UNDECLARED_SELECTOR = YES; 455 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 456 | GCC_WARN_UNUSED_FUNCTION = YES; 457 | GCC_WARN_UNUSED_VARIABLE = YES; 458 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 459 | MTL_ENABLE_DEBUG_INFO = NO; 460 | SDKROOT = iphoneos; 461 | TARGETED_DEVICE_FAMILY = "1,2"; 462 | VALIDATE_PRODUCT = YES; 463 | VERSIONING_SYSTEM = "apple-generic"; 464 | VERSION_INFO_PREFIX = ""; 465 | }; 466 | name = Release; 467 | }; 468 | D5B2E8B41C3A780C00C0327D /* Debug */ = { 469 | isa = XCBuildConfiguration; 470 | buildSettings = { 471 | CLANG_ENABLE_MODULES = YES; 472 | DEFINES_MODULE = YES; 473 | DYLIB_COMPATIBILITY_VERSION = 1; 474 | DYLIB_CURRENT_VERSION = 1; 475 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 476 | INFOPLIST_FILE = "$(SRCROOT)/MainThreadGuard/Info-iOS.plist"; 477 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 478 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 480 | PRODUCT_BUNDLE_IDENTIFIER = "com.fantageek.MainThreadGuard.MainThreadGuard-iOS"; 481 | PRODUCT_NAME = MainThreadGuard; 482 | SKIP_INSTALL = YES; 483 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 484 | SWIFT_VERSION = 3.0; 485 | }; 486 | name = Debug; 487 | }; 488 | D5B2E8B51C3A780C00C0327D /* Release */ = { 489 | isa = XCBuildConfiguration; 490 | buildSettings = { 491 | CLANG_ENABLE_MODULES = YES; 492 | DEFINES_MODULE = YES; 493 | DYLIB_COMPATIBILITY_VERSION = 1; 494 | DYLIB_CURRENT_VERSION = 1; 495 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 496 | INFOPLIST_FILE = "$(SRCROOT)/MainThreadGuard/Info-iOS.plist"; 497 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 498 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 499 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 500 | PRODUCT_BUNDLE_IDENTIFIER = "com.fantageek.MainThreadGuard.MainThreadGuard-iOS"; 501 | PRODUCT_NAME = MainThreadGuard; 502 | SKIP_INSTALL = YES; 503 | SWIFT_VERSION = 3.0; 504 | }; 505 | name = Release; 506 | }; 507 | D5B2E8B71C3A780C00C0327D /* Debug */ = { 508 | isa = XCBuildConfiguration; 509 | buildSettings = { 510 | CLANG_ENABLE_MODULES = YES; 511 | FRAMEWORK_SEARCH_PATHS = ( 512 | "$(inherited)", 513 | "$(FRAMEWORK_SEARCH_PATHS)", 514 | ); 515 | INFOPLIST_FILE = "$(SRCROOT)/MainThreadGuardTests/Info-iOS.plist"; 516 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 517 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.MainThreadGuardTests; 518 | PRODUCT_NAME = "$(TARGET_NAME)"; 519 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 520 | SWIFT_VERSION = 3.0; 521 | }; 522 | name = Debug; 523 | }; 524 | D5B2E8B81C3A780C00C0327D /* Release */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | CLANG_ENABLE_MODULES = YES; 528 | FRAMEWORK_SEARCH_PATHS = ( 529 | "$(inherited)", 530 | "$(FRAMEWORK_SEARCH_PATHS)", 531 | ); 532 | INFOPLIST_FILE = "$(SRCROOT)/MainThreadGuardTests/Info-iOS.plist"; 533 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 534 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.MainThreadGuardTests; 535 | PRODUCT_NAME = "$(TARGET_NAME)"; 536 | SWIFT_VERSION = 3.0; 537 | }; 538 | name = Release; 539 | }; 540 | D5C629521C3A7FAA007F7B7C /* Debug */ = { 541 | isa = XCBuildConfiguration; 542 | buildSettings = { 543 | CLANG_ENABLE_MODULES = YES; 544 | CODE_SIGN_IDENTITY = "-"; 545 | COMBINE_HIDPI_IMAGES = YES; 546 | DEFINES_MODULE = YES; 547 | DYLIB_COMPATIBILITY_VERSION = 1; 548 | DYLIB_CURRENT_VERSION = 1; 549 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 550 | FRAMEWORK_VERSION = A; 551 | INFOPLIST_FILE = "$(SRCROOT)/MainThreadGuard/Info-Mac.plist"; 552 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 553 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 554 | MACOSX_DEPLOYMENT_TARGET = 10.9; 555 | PRODUCT_BUNDLE_IDENTIFIER = "com.fantageek.MainThreadGuard.MainThreadGuard-Mac"; 556 | PRODUCT_NAME = MainThreadGuard; 557 | SDKROOT = macosx; 558 | SKIP_INSTALL = YES; 559 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 560 | }; 561 | name = Debug; 562 | }; 563 | D5C629531C3A7FAA007F7B7C /* Release */ = { 564 | isa = XCBuildConfiguration; 565 | buildSettings = { 566 | CLANG_ENABLE_MODULES = YES; 567 | CODE_SIGN_IDENTITY = "-"; 568 | COMBINE_HIDPI_IMAGES = YES; 569 | DEFINES_MODULE = YES; 570 | DYLIB_COMPATIBILITY_VERSION = 1; 571 | DYLIB_CURRENT_VERSION = 1; 572 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 573 | FRAMEWORK_VERSION = A; 574 | INFOPLIST_FILE = "$(SRCROOT)/MainThreadGuard/Info-Mac.plist"; 575 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 576 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 577 | MACOSX_DEPLOYMENT_TARGET = 10.9; 578 | PRODUCT_BUNDLE_IDENTIFIER = "com.fantageek.MainThreadGuard.MainThreadGuard-Mac"; 579 | PRODUCT_NAME = MainThreadGuard; 580 | SDKROOT = macosx; 581 | SKIP_INSTALL = YES; 582 | }; 583 | name = Release; 584 | }; 585 | D5C629551C3A7FAA007F7B7C /* Debug */ = { 586 | isa = XCBuildConfiguration; 587 | buildSettings = { 588 | CODE_SIGN_IDENTITY = "-"; 589 | COMBINE_HIDPI_IMAGES = YES; 590 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 591 | INFOPLIST_FILE = "$(SRCROOT)/MainThreadGuardTests/Info-Mac.plist"; 592 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 593 | MACOSX_DEPLOYMENT_TARGET = 10.11; 594 | PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.MainThreadGuard-MacTests"; 595 | PRODUCT_NAME = "$(TARGET_NAME)"; 596 | SDKROOT = macosx; 597 | }; 598 | name = Debug; 599 | }; 600 | D5C629561C3A7FAA007F7B7C /* Release */ = { 601 | isa = XCBuildConfiguration; 602 | buildSettings = { 603 | CODE_SIGN_IDENTITY = "-"; 604 | COMBINE_HIDPI_IMAGES = YES; 605 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 606 | INFOPLIST_FILE = "$(SRCROOT)/MainThreadGuardTests/Info-Mac.plist"; 607 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 608 | MACOSX_DEPLOYMENT_TARGET = 10.11; 609 | PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.MainThreadGuard-MacTests"; 610 | PRODUCT_NAME = "$(TARGET_NAME)"; 611 | SDKROOT = macosx; 612 | }; 613 | name = Release; 614 | }; 615 | /* End XCBuildConfiguration section */ 616 | 617 | /* Begin XCConfigurationList section */ 618 | D5B2E8991C3A780C00C0327D /* Build configuration list for PBXProject "MainThreadGuard" */ = { 619 | isa = XCConfigurationList; 620 | buildConfigurations = ( 621 | D5B2E8B11C3A780C00C0327D /* Debug */, 622 | D5B2E8B21C3A780C00C0327D /* Release */, 623 | ); 624 | defaultConfigurationIsVisible = 0; 625 | defaultConfigurationName = Release; 626 | }; 627 | D5B2E8B31C3A780C00C0327D /* Build configuration list for PBXNativeTarget "MainThreadGuard-iOS" */ = { 628 | isa = XCConfigurationList; 629 | buildConfigurations = ( 630 | D5B2E8B41C3A780C00C0327D /* Debug */, 631 | D5B2E8B51C3A780C00C0327D /* Release */, 632 | ); 633 | defaultConfigurationIsVisible = 0; 634 | defaultConfigurationName = Release; 635 | }; 636 | D5B2E8B61C3A780C00C0327D /* Build configuration list for PBXNativeTarget "MainThreadGuard-iOS-Tests" */ = { 637 | isa = XCConfigurationList; 638 | buildConfigurations = ( 639 | D5B2E8B71C3A780C00C0327D /* Debug */, 640 | D5B2E8B81C3A780C00C0327D /* Release */, 641 | ); 642 | defaultConfigurationIsVisible = 0; 643 | defaultConfigurationName = Release; 644 | }; 645 | D5C629511C3A7FAA007F7B7C /* Build configuration list for PBXNativeTarget "MainThreadGuard-Mac" */ = { 646 | isa = XCConfigurationList; 647 | buildConfigurations = ( 648 | D5C629521C3A7FAA007F7B7C /* Debug */, 649 | D5C629531C3A7FAA007F7B7C /* Release */, 650 | ); 651 | defaultConfigurationIsVisible = 0; 652 | defaultConfigurationName = Release; 653 | }; 654 | D5C629541C3A7FAA007F7B7C /* Build configuration list for PBXNativeTarget "MainThreadGuard-Mac-Tests" */ = { 655 | isa = XCConfigurationList; 656 | buildConfigurations = ( 657 | D5C629551C3A7FAA007F7B7C /* Debug */, 658 | D5C629561C3A7FAA007F7B7C /* Release */, 659 | ); 660 | defaultConfigurationIsVisible = 0; 661 | defaultConfigurationName = Release; 662 | }; 663 | /* End XCConfigurationList section */ 664 | }; 665 | rootObject = D5B2E8961C3A780C00C0327D /* Project object */; 666 | } 667 | -------------------------------------------------------------------------------- /MainThreadGuard.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MainThreadGuard.xcodeproj/xcshareddata/xcschemes/MainThreadGuard-Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /MainThreadGuard.xcodeproj/xcshareddata/xcschemes/MainThreadGuard-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /MainThreadGuard/Info-Mac.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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2016 Hyper Interaktiv AS. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /MainThreadGuard/Info-iOS.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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /MainThreadGuardTests/Info-Mac.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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /MainThreadGuardTests/Info-iOS.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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Playground-Mac.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // MainThreadGuard Mac Playground 2 | 3 | import Cocoa 4 | import MainThreadGuard 5 | 6 | var str = "Hello, playground" 7 | -------------------------------------------------------------------------------- /Playground-Mac.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Playground-Mac.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Playground-iOS.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // MainThreadGuard iOS Playground 2 | 3 | import UIKit 4 | import MainThreadGuard 5 | 6 | var str = "Hello, playground" 7 | -------------------------------------------------------------------------------- /Playground-iOS.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Playground-iOS.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MainThreadGuard 2 | Tracking UIKit access on main thread 3 | 4 | [![Version](https://img.shields.io/cocoapods/v/MainThreadGuard.svg?style=flat)](http://cocoapods.org/pods/MainThreadGuard) 5 | [![License](https://img.shields.io/cocoapods/l/MainThreadGuard.svg?style=flat)](http://cocoapods.org/pods/MainThreadGuard) 6 | [![Platform](https://img.shields.io/cocoapods/p/MainThreadGuard.svg?style=flat)](http://cocoapods.org/pods/MainThreadGuard) 7 | ![Swift](https://img.shields.io/badge/%20in-swift%203.0-orange.svg) 8 | 9 | ![](Screenshots/Banner.png) 10 | 11 | ## Description 12 | 13 | This is just a Swift port of [PSPDFUIKitMainThreadGuard.m](https://gist.github.com/steipete/5664345) using swizzling on `UIView` extension 14 | 15 | ## Usage 16 | 17 | Call `Guard.setup` 18 | 19 | ```swift 20 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 21 | // setup 22 | 23 | Guard.setup() 24 | 25 | return true 26 | } 27 | ``` 28 | 29 | ## Features 30 | 31 | It works by swizzling in the following methods 32 | 33 | - setNeedsLayout 34 | - setNeedsDisplay 35 | - setNeedsDisplayInRect: 36 | 37 | Try accessing UIKit from another thread and MainThreadGuard will assert 38 | 39 | ```swift 40 | class ViewController: UIViewController { 41 | 42 | override func viewDidLoad() { 43 | super.viewDidLoad() 44 | view.backgroundColor = UIColor.white 45 | 46 | let label = UILabel() 47 | view.addSubview(label) 48 | 49 | DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async { 50 | label.text = "Setting text on background thread" 51 | } 52 | } 53 | } 54 | ``` 55 | 56 | ## Xcode 9+ 57 | 58 | Xcode 9+ has [Main Thread Checker](https://developer.apple.com/documentation/code_diagnostics/main_thread_checker), which detects invalid use of AppKit, UIKit, and other APIs from a background thread. 59 | 60 | ## Installation 61 | 62 | MainThreadGuard is available through [CocoaPods](http://cocoapods.org). To install 63 | it, simply add the following line to your Podfile: 64 | 65 | You should add this to Debug configuration only 66 | 67 | ```ruby 68 | pod "MainThreadGuard", git: 'https://github.com/onmyway133/MainThreadGuard', configurations: 'Debug' 69 | ``` 70 | 71 | ## Author 72 | 73 | Khoa Pham, onmyway133@gmail.com 74 | 75 | ## License 76 | 77 | MainThreadGuard is available under the MIT license. See the LICENSE file for more info. 78 | -------------------------------------------------------------------------------- /Screenshots/Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onmyway133/MainThreadGuard/a83926fc988287cbac990cba32a3366ccb5b8714/Screenshots/Banner.png -------------------------------------------------------------------------------- /Sources/MainThreadGuard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainThreadGuard.swift 3 | // MainThreadGuard 4 | // 5 | // Created by Khoa Pham on 30/04/16. 6 | // Copyright © 2016 Fantageek. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | // Reference: 13 | // http://nshipster.com/swift-objc-runtime/ 14 | // https://gist.github.com/steipete/5664345 15 | 16 | public class Guard { 17 | 18 | public static func setup() { 19 | UIView.setupForMainThreadGuard() 20 | } 21 | } 22 | 23 | extension UIView { 24 | 25 | static func setupForMainThreadGuard() { 26 | struct Static { 27 | static let token = UUID().uuidString 28 | } 29 | 30 | // make sure this isn't a subclass 31 | if self !== UIView.self { 32 | return 33 | } 34 | 35 | DispatchQueue.mainThreadGuard_once(Static.token) { 36 | let swizzle: (String, String) -> Void = { (original, swizzled) in 37 | let originalSelector = Selector(original) 38 | let swizzledSelector = Selector(swizzled) 39 | 40 | let originalMethod = class_getInstanceMethod(self, originalSelector) 41 | let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) 42 | 43 | let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) 44 | 45 | if didAddMethod { 46 | class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) 47 | } else { 48 | method_exchangeImplementations(originalMethod, swizzledMethod) 49 | } 50 | } 51 | 52 | let pairs: [String: String] = [ 53 | "setNeedsLayout": "guard_setNeedsLayout", 54 | "setNeedsDisplay": "guard_setNeedsDisplay", 55 | "setNeedsDisplayInRect:": "guard_setNeedsDisplayInRect:" 56 | ] 57 | 58 | pairs.forEach { (key, value) in 59 | swizzle(key, value) 60 | } 61 | } 62 | } 63 | 64 | // MARK: Method Swizzling 65 | 66 | func guard_setNeedsLayout() { 67 | guard_check() 68 | guard_setNeedsLayout() 69 | } 70 | 71 | func guard_setNeedsDisplay() { 72 | guard_check() 73 | guard_setNeedsDisplay() 74 | } 75 | 76 | func guard_setNeedsDisplayInRect(_ rect: CGRect) { 77 | guard_check() 78 | guard_setNeedsDisplayInRect(rect) 79 | } 80 | 81 | // MARK: Checking 82 | func guard_check() { 83 | assert(Thread.isMainThread) 84 | 85 | // iOS 8 layouts the MFMailComposeController in a background thread on an UIKit queue. 86 | } 87 | } 88 | 89 | private extension DispatchQueue { 90 | 91 | static var mainThreadGuardTokens = [String]() 92 | 93 | class func mainThreadGuard_once(_ token: String, closure: () -> Void) { 94 | objc_sync_enter(self) 95 | 96 | defer { 97 | objc_sync_exit(self) 98 | } 99 | 100 | guard !mainThreadGuardTokens.contains(token) else { 101 | return 102 | } 103 | 104 | mainThreadGuardTokens.append(token) 105 | closure() 106 | } 107 | } 108 | --------------------------------------------------------------------------------