├── .gitignore ├── GCDObjC.podspec ├── GCDObjC.xcodeproj └── project.pbxproj ├── GCDObjC ├── GCDGroup.h ├── GCDGroup.m ├── GCDMacros.h ├── GCDObjC.h ├── GCDQueue.h ├── GCDQueue.m ├── GCDSemaphore.h └── GCDSemaphore.m ├── GCDObjCTests ├── GCDObjCTests-Info.plist └── GCDObjCTests.m ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /DerivedData/ 3 | /GCDObjC.xcodeproj/project.xcworkspace/ 4 | /GCDObjC.xcodeproj/xcuserdata/ 5 | -------------------------------------------------------------------------------- /GCDObjC.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "GCDObjC" 3 | s.version = "0.3.0" 4 | s.summary = "Objective-C wrapper for Grand Central Dispatch." 5 | s.description = <<-DESC 6 | GCDObjC is an Objective-C wrapper for the most commonly used features of Grand Central Dispatch. 7 | It has four main aims: 8 | 9 | * Organize the flat C API into appropriate classes. 10 | * Use intention-revealing names to distinguish between synchronous and asynchronous functions. 11 | * Use more convenient arguments such as NSTimeIntervals. 12 | * Add convenience methods. 13 | DESC 14 | s.homepage = "https://github.com/mjmsmith/gcdobjc" 15 | s.license = { :type => "MIT", :file => "LICENSE" } 16 | s.author = { "Mark Smith" => "mark@camazotz.com" } 17 | s.platform = :ios, "6.0" 18 | s.source = { :git => "https://github.com/mjmsmith/gcdobjc.git", :tag => "v#{s.version}" } 19 | s.source_files = "GCDObjC" 20 | s.requires_arc = true 21 | end 22 | -------------------------------------------------------------------------------- /GCDObjC.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4D06C16E158EB92300CBC711 /* GCDObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D06C16D158EB92200CBC711 /* GCDObjC.h */; }; 11 | 4D06C1D4158EDF9F00CBC711 /* GCDSemaphore.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D930E69158D728B009538FB /* GCDSemaphore.m */; }; 12 | 4D06C1D6158EDFA300CBC711 /* GCDGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D930E64158D71F7009538FB /* GCDGroup.m */; }; 13 | 4D6F601C158414F70023150C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D6F601B158414F70023150C /* Foundation.framework */; }; 14 | 4D6F602D158414F70023150C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D6F601B158414F70023150C /* Foundation.framework */; }; 15 | 4D6F6030158414F70023150C /* libGCDObjC.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D6F6018158414F70023150C /* libGCDObjC.a */; }; 16 | 4D6F6039158414F70023150C /* GCDObjCTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D6F6038158414F70023150C /* GCDObjCTests.m */; }; 17 | 4D6F60441584152C0023150C /* GCDQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D6F60421584152C0023150C /* GCDQueue.h */; }; 18 | 4D6F60451584152C0023150C /* GCDQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D6F60431584152C0023150C /* GCDQueue.m */; }; 19 | 4D6F60461584152C0023150C /* GCDQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D6F60431584152C0023150C /* GCDQueue.m */; }; 20 | 4D930E65158D71F7009538FB /* GCDGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D930E63158D71F7009538FB /* GCDGroup.h */; }; 21 | 4D930E66158D71F7009538FB /* GCDGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D930E64158D71F7009538FB /* GCDGroup.m */; }; 22 | 4D930E6A158D728B009538FB /* GCDSemaphore.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D930E68158D728B009538FB /* GCDSemaphore.h */; }; 23 | 4D930E6B158D728B009538FB /* GCDSemaphore.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D930E69158D728B009538FB /* GCDSemaphore.m */; }; 24 | 4DD3B37818344525007E05BA /* GCDMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD3B37718344525007E05BA /* GCDMacros.h */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | 4D6F602E158414F70023150C /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 4D6F600F158414F60023150C /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = 4D6F6017158414F60023150C; 33 | remoteInfo = GCDObjC; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 4D06C16D158EB92200CBC711 /* GCDObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDObjC.h; sourceTree = ""; }; 39 | 4D6F6018158414F70023150C /* libGCDObjC.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libGCDObjC.a; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | 4D6F601B158414F70023150C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 41 | 4D6F6028158414F70023150C /* GCDObjCTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GCDObjCTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 4D6F6038158414F70023150C /* GCDObjCTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GCDObjCTests.m; sourceTree = ""; }; 43 | 4D6F60421584152C0023150C /* GCDQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDQueue.h; sourceTree = ""; }; 44 | 4D6F60431584152C0023150C /* GCDQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDQueue.m; sourceTree = ""; }; 45 | 4D930E63158D71F7009538FB /* GCDGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDGroup.h; sourceTree = ""; }; 46 | 4D930E64158D71F7009538FB /* GCDGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDGroup.m; sourceTree = ""; }; 47 | 4D930E68158D728B009538FB /* GCDSemaphore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDSemaphore.h; sourceTree = ""; }; 48 | 4D930E69158D728B009538FB /* GCDSemaphore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDSemaphore.m; sourceTree = ""; }; 49 | 4DD3B37718344525007E05BA /* GCDMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDMacros.h; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 4D6F6015158414F60023150C /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | 4D6F601C158414F70023150C /* Foundation.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | 4D6F6024158414F70023150C /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | 4D6F602D158414F70023150C /* Foundation.framework in Frameworks */, 66 | 4D6F6030158414F70023150C /* libGCDObjC.a in Frameworks */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXFrameworksBuildPhase section */ 71 | 72 | /* Begin PBXGroup section */ 73 | 4D6F600D158414F60023150C = { 74 | isa = PBXGroup; 75 | children = ( 76 | 4D6F601D158414F70023150C /* GCDObjC */, 77 | 4D6F6031158414F70023150C /* GCDObjCTests */, 78 | 4D6F601A158414F70023150C /* Frameworks */, 79 | 4D6F6019158414F70023150C /* Products */, 80 | ); 81 | sourceTree = ""; 82 | }; 83 | 4D6F6019158414F70023150C /* Products */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 4D6F6018158414F70023150C /* libGCDObjC.a */, 87 | 4D6F6028158414F70023150C /* GCDObjCTests.xctest */, 88 | ); 89 | name = Products; 90 | sourceTree = ""; 91 | }; 92 | 4D6F601A158414F70023150C /* Frameworks */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 4D6F601B158414F70023150C /* Foundation.framework */, 96 | ); 97 | name = Frameworks; 98 | sourceTree = ""; 99 | }; 100 | 4D6F601D158414F70023150C /* GCDObjC */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 4D06C16D158EB92200CBC711 /* GCDObjC.h */, 104 | 4D930E63158D71F7009538FB /* GCDGroup.h */, 105 | 4D930E64158D71F7009538FB /* GCDGroup.m */, 106 | 4D6F60421584152C0023150C /* GCDQueue.h */, 107 | 4D6F60431584152C0023150C /* GCDQueue.m */, 108 | 4D930E68158D728B009538FB /* GCDSemaphore.h */, 109 | 4D930E69158D728B009538FB /* GCDSemaphore.m */, 110 | 4DD3B37718344525007E05BA /* GCDMacros.h */, 111 | ); 112 | path = GCDObjC; 113 | sourceTree = ""; 114 | }; 115 | 4D6F6031158414F70023150C /* GCDObjCTests */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 4D6F6038158414F70023150C /* GCDObjCTests.m */, 119 | ); 120 | path = GCDObjCTests; 121 | sourceTree = ""; 122 | }; 123 | /* End PBXGroup section */ 124 | 125 | /* Begin PBXHeadersBuildPhase section */ 126 | 4D6F6016158414F60023150C /* Headers */ = { 127 | isa = PBXHeadersBuildPhase; 128 | buildActionMask = 2147483647; 129 | files = ( 130 | 4D6F60441584152C0023150C /* GCDQueue.h in Headers */, 131 | 4D930E65158D71F7009538FB /* GCDGroup.h in Headers */, 132 | 4DD3B37818344525007E05BA /* GCDMacros.h in Headers */, 133 | 4D930E6A158D728B009538FB /* GCDSemaphore.h in Headers */, 134 | 4D06C16E158EB92300CBC711 /* GCDObjC.h in Headers */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXHeadersBuildPhase section */ 139 | 140 | /* Begin PBXNativeTarget section */ 141 | 4D6F6017158414F60023150C /* GCDObjC */ = { 142 | isa = PBXNativeTarget; 143 | buildConfigurationList = 4D6F603C158414F70023150C /* Build configuration list for PBXNativeTarget "GCDObjC" */; 144 | buildPhases = ( 145 | 4D6F6014158414F60023150C /* Sources */, 146 | 4D6F6015158414F60023150C /* Frameworks */, 147 | 4D6F6016158414F60023150C /* Headers */, 148 | ); 149 | buildRules = ( 150 | ); 151 | dependencies = ( 152 | ); 153 | name = GCDObjC; 154 | productName = GCDObjC; 155 | productReference = 4D6F6018158414F70023150C /* libGCDObjC.a */; 156 | productType = "com.apple.product-type.library.static"; 157 | }; 158 | 4D6F6027158414F70023150C /* GCDObjCTests */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = 4D6F603F158414F70023150C /* Build configuration list for PBXNativeTarget "GCDObjCTests" */; 161 | buildPhases = ( 162 | 4D6F6023158414F70023150C /* Sources */, 163 | 4D6F6024158414F70023150C /* Frameworks */, 164 | 4D6F6025158414F70023150C /* Resources */, 165 | 4D6F6026158414F70023150C /* ShellScript */, 166 | ); 167 | buildRules = ( 168 | ); 169 | dependencies = ( 170 | 4D6F602F158414F70023150C /* PBXTargetDependency */, 171 | ); 172 | name = GCDObjCTests; 173 | productName = GCDObjCTests; 174 | productReference = 4D6F6028158414F70023150C /* GCDObjCTests.xctest */; 175 | productType = "com.apple.product-type.bundle.unit-test"; 176 | }; 177 | /* End PBXNativeTarget section */ 178 | 179 | /* Begin PBXProject section */ 180 | 4D6F600F158414F60023150C /* Project object */ = { 181 | isa = PBXProject; 182 | attributes = { 183 | LastUpgradeCheck = 0700; 184 | }; 185 | buildConfigurationList = 4D6F6012158414F60023150C /* Build configuration list for PBXProject "GCDObjC" */; 186 | compatibilityVersion = "Xcode 3.2"; 187 | developmentRegion = English; 188 | hasScannedForEncodings = 0; 189 | knownRegions = ( 190 | en, 191 | ); 192 | mainGroup = 4D6F600D158414F60023150C; 193 | productRefGroup = 4D6F6019158414F70023150C /* Products */; 194 | projectDirPath = ""; 195 | projectRoot = ""; 196 | targets = ( 197 | 4D6F6017158414F60023150C /* GCDObjC */, 198 | 4D6F6027158414F70023150C /* GCDObjCTests */, 199 | ); 200 | }; 201 | /* End PBXProject section */ 202 | 203 | /* Begin PBXResourcesBuildPhase section */ 204 | 4D6F6025158414F70023150C /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXResourcesBuildPhase section */ 212 | 213 | /* Begin PBXShellScriptBuildPhase section */ 214 | 4D6F6026158414F70023150C /* ShellScript */ = { 215 | isa = PBXShellScriptBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | ); 219 | inputPaths = ( 220 | ); 221 | outputPaths = ( 222 | ); 223 | runOnlyForDeploymentPostprocessing = 0; 224 | shellPath = /bin/sh; 225 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 226 | }; 227 | /* End PBXShellScriptBuildPhase section */ 228 | 229 | /* Begin PBXSourcesBuildPhase section */ 230 | 4D6F6014158414F60023150C /* Sources */ = { 231 | isa = PBXSourcesBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | 4D6F60451584152C0023150C /* GCDQueue.m in Sources */, 235 | 4D930E66158D71F7009538FB /* GCDGroup.m in Sources */, 236 | 4D930E6B158D728B009538FB /* GCDSemaphore.m in Sources */, 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | }; 240 | 4D6F6023158414F70023150C /* Sources */ = { 241 | isa = PBXSourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | 4D6F6039158414F70023150C /* GCDObjCTests.m in Sources */, 245 | 4D06C1D6158EDFA300CBC711 /* GCDGroup.m in Sources */, 246 | 4D6F60461584152C0023150C /* GCDQueue.m in Sources */, 247 | 4D06C1D4158EDF9F00CBC711 /* GCDSemaphore.m in Sources */, 248 | ); 249 | runOnlyForDeploymentPostprocessing = 0; 250 | }; 251 | /* End PBXSourcesBuildPhase section */ 252 | 253 | /* Begin PBXTargetDependency section */ 254 | 4D6F602F158414F70023150C /* PBXTargetDependency */ = { 255 | isa = PBXTargetDependency; 256 | target = 4D6F6017158414F60023150C /* GCDObjC */; 257 | targetProxy = 4D6F602E158414F70023150C /* PBXContainerItemProxy */; 258 | }; 259 | /* End PBXTargetDependency section */ 260 | 261 | /* Begin XCBuildConfiguration section */ 262 | 4D6F603A158414F70023150C /* Debug */ = { 263 | isa = XCBuildConfiguration; 264 | buildSettings = { 265 | ALWAYS_SEARCH_USER_PATHS = NO; 266 | CLANG_ENABLE_OBJC_ARC = YES; 267 | CLANG_WARN_BOOL_CONVERSION = YES; 268 | CLANG_WARN_CONSTANT_CONVERSION = YES; 269 | CLANG_WARN_EMPTY_BODY = YES; 270 | CLANG_WARN_ENUM_CONVERSION = YES; 271 | CLANG_WARN_INT_CONVERSION = YES; 272 | CLANG_WARN_UNREACHABLE_CODE = YES; 273 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 274 | COPY_PHASE_STRIP = NO; 275 | ENABLE_STRICT_OBJC_MSGSEND = YES; 276 | ENABLE_TESTABILITY = YES; 277 | GCC_C_LANGUAGE_STANDARD = gnu99; 278 | GCC_DYNAMIC_NO_PIC = NO; 279 | GCC_NO_COMMON_BLOCKS = YES; 280 | GCC_OPTIMIZATION_LEVEL = 0; 281 | GCC_PREPROCESSOR_DEFINITIONS = ( 282 | "DEBUG=1", 283 | "$(inherited)", 284 | ); 285 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 286 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 287 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 288 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 289 | GCC_WARN_UNDECLARED_SELECTOR = YES; 290 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 291 | GCC_WARN_UNUSED_FUNCTION = YES; 292 | GCC_WARN_UNUSED_VARIABLE = YES; 293 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 294 | ONLY_ACTIVE_ARCH = YES; 295 | SDKROOT = iphoneos; 296 | }; 297 | name = Debug; 298 | }; 299 | 4D6F603B158414F70023150C /* Release */ = { 300 | isa = XCBuildConfiguration; 301 | buildSettings = { 302 | ALWAYS_SEARCH_USER_PATHS = NO; 303 | CLANG_ENABLE_OBJC_ARC = YES; 304 | CLANG_WARN_BOOL_CONVERSION = YES; 305 | CLANG_WARN_CONSTANT_CONVERSION = YES; 306 | CLANG_WARN_EMPTY_BODY = YES; 307 | CLANG_WARN_ENUM_CONVERSION = YES; 308 | CLANG_WARN_INT_CONVERSION = YES; 309 | CLANG_WARN_UNREACHABLE_CODE = YES; 310 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 311 | COPY_PHASE_STRIP = YES; 312 | ENABLE_STRICT_OBJC_MSGSEND = YES; 313 | GCC_C_LANGUAGE_STANDARD = gnu99; 314 | GCC_NO_COMMON_BLOCKS = YES; 315 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 316 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 317 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 318 | GCC_WARN_UNDECLARED_SELECTOR = YES; 319 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 320 | GCC_WARN_UNUSED_FUNCTION = YES; 321 | GCC_WARN_UNUSED_VARIABLE = YES; 322 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 323 | SDKROOT = iphoneos; 324 | VALIDATE_PRODUCT = YES; 325 | }; 326 | name = Release; 327 | }; 328 | 4D6F603D158414F70023150C /* Debug */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | DSTROOT = /tmp/GCDObjC.dst; 332 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 333 | GCC_PREFIX_HEADER = ""; 334 | OTHER_LDFLAGS = "-ObjC"; 335 | PRODUCT_NAME = "$(TARGET_NAME)"; 336 | SKIP_INSTALL = YES; 337 | }; 338 | name = Debug; 339 | }; 340 | 4D6F603E158414F70023150C /* Release */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | DSTROOT = /tmp/GCDObjC.dst; 344 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 345 | GCC_PREFIX_HEADER = ""; 346 | OTHER_LDFLAGS = "-ObjC"; 347 | PRODUCT_NAME = "$(TARGET_NAME)"; 348 | SKIP_INSTALL = YES; 349 | }; 350 | name = Release; 351 | }; 352 | 4D6F6040158414F70023150C /* Debug */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)/Developer/Library/Frameworks"; 356 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 357 | INFOPLIST_FILE = "GCDObjCTests/GCDObjCTests-Info.plist"; 358 | PRODUCT_BUNDLE_IDENTIFIER = "com.camazotz.${PRODUCT_NAME:rfc1034identifier}"; 359 | PRODUCT_NAME = "$(TARGET_NAME)"; 360 | }; 361 | name = Debug; 362 | }; 363 | 4D6F6041158414F70023150C /* Release */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)/Developer/Library/Frameworks"; 367 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 368 | INFOPLIST_FILE = "GCDObjCTests/GCDObjCTests-Info.plist"; 369 | PRODUCT_BUNDLE_IDENTIFIER = "com.camazotz.${PRODUCT_NAME:rfc1034identifier}"; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | }; 372 | name = Release; 373 | }; 374 | /* End XCBuildConfiguration section */ 375 | 376 | /* Begin XCConfigurationList section */ 377 | 4D6F6012158414F60023150C /* Build configuration list for PBXProject "GCDObjC" */ = { 378 | isa = XCConfigurationList; 379 | buildConfigurations = ( 380 | 4D6F603A158414F70023150C /* Debug */, 381 | 4D6F603B158414F70023150C /* Release */, 382 | ); 383 | defaultConfigurationIsVisible = 0; 384 | defaultConfigurationName = Release; 385 | }; 386 | 4D6F603C158414F70023150C /* Build configuration list for PBXNativeTarget "GCDObjC" */ = { 387 | isa = XCConfigurationList; 388 | buildConfigurations = ( 389 | 4D6F603D158414F70023150C /* Debug */, 390 | 4D6F603E158414F70023150C /* Release */, 391 | ); 392 | defaultConfigurationIsVisible = 0; 393 | defaultConfigurationName = Release; 394 | }; 395 | 4D6F603F158414F70023150C /* Build configuration list for PBXNativeTarget "GCDObjCTests" */ = { 396 | isa = XCConfigurationList; 397 | buildConfigurations = ( 398 | 4D6F6040158414F70023150C /* Debug */, 399 | 4D6F6041158414F70023150C /* Release */, 400 | ); 401 | defaultConfigurationIsVisible = 0; 402 | defaultConfigurationName = Release; 403 | }; 404 | /* End XCConfigurationList section */ 405 | }; 406 | rootObject = 4D6F600F158414F60023150C /* Project object */; 407 | } 408 | -------------------------------------------------------------------------------- /GCDObjC/GCDGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCDGroup.h 3 | // GCDObjC 4 | // 5 | // Copyright (c) 2012 Mark Smith. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface GCDGroup : NSObject 11 | 12 | /** 13 | * Returns the underlying dispatch group object. 14 | * 15 | * @return The dispatch group object. 16 | */ 17 | @property (strong, readonly, nonatomic) dispatch_group_t dispatchGroup; 18 | 19 | /** 20 | * Initializes a new group. 21 | * 22 | * @return The initialized instance. 23 | * @see dispatch_group_create() 24 | */ 25 | - (instancetype)init; 26 | 27 | /** 28 | * The GCDGroup designated initializer. 29 | * 30 | * @param dispatchGroup A dispatch_group_t object. 31 | * @return The initialized instance. 32 | */ 33 | - (instancetype)initWithDispatchGroup:(dispatch_group_t)dispatchGroup; 34 | 35 | /** 36 | * Explicitly indicates that a block has entered the group. 37 | * 38 | * @see dispatch_group_enter() 39 | */ 40 | - (void)enter; 41 | 42 | /** 43 | * Explicitly indicates that a block in the group has completed. 44 | * 45 | * @see dispatch_group_leave() 46 | */ 47 | - (void)leave; 48 | 49 | /** 50 | * Waits forever for the previously submitted blocks in the group to complete. 51 | * 52 | * @see dispatch_group_wait() 53 | */ 54 | - (void)wait; 55 | 56 | /** 57 | * Waits for the previously submitted blocks in the group to complete. 58 | * 59 | * @param seconds The time to wait in seconds. 60 | * @return YES if all blocks completed, NO if the timeout occurred. 61 | * @see dispatch_group_wait() 62 | */ 63 | - (BOOL)wait:(double)seconds; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /GCDObjC/GCDGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // GCDGroup.m 3 | // GCDObjC 4 | // 5 | // Copyright (c) 2012 Mark Smith. All rights reserved. 6 | // 7 | 8 | #import "GCDGroup.h" 9 | 10 | @interface GCDGroup () 11 | @property (strong, readwrite, nonatomic) dispatch_group_t dispatchGroup; 12 | @end 13 | 14 | @implementation GCDGroup 15 | 16 | #pragma mark Lifecycle. 17 | 18 | - (instancetype)init { 19 | return [self initWithDispatchGroup:dispatch_group_create()]; 20 | } 21 | 22 | - (instancetype)initWithDispatchGroup:(dispatch_group_t)dispatchGroup { 23 | if ((self = [super init]) != nil) { 24 | self.dispatchGroup = dispatchGroup; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | #pragma mark Public methods. 31 | 32 | - (void)enter { 33 | dispatch_group_enter(self.dispatchGroup); 34 | } 35 | 36 | - (void)leave { 37 | dispatch_group_leave(self.dispatchGroup); 38 | } 39 | 40 | - (void)wait { 41 | dispatch_group_wait(self.dispatchGroup, DISPATCH_TIME_FOREVER); 42 | } 43 | 44 | - (BOOL)wait:(double)seconds { 45 | return dispatch_group_wait(self.dispatchGroup, dispatch_time(DISPATCH_TIME_NOW, (seconds * NSEC_PER_SEC))) == 0; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /GCDObjC/GCDMacros.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCDMacros.h 3 | // GCDObjC 4 | // 5 | // Copyright (c) 2013 Mark Smith. All rights reserved. 6 | // 7 | // 8 | 9 | /** 10 | * Inserts code that executes a block only once, regardless of how many times the macro is invoked. 11 | * 12 | * @param block The block to execute once. 13 | */ 14 | #ifndef GCDExecOnce 15 | #define GCDExecOnce(block) \ 16 | { \ 17 | static dispatch_once_t predicate = 0; \ 18 | dispatch_once(&predicate, block); \ 19 | } 20 | #endif 21 | 22 | /** 23 | * Inserts code that declares, creates, and returns a single instance, regardless of how many times the macro is invoked. 24 | * 25 | * @param block A block that creates and returns the instance value. 26 | */ 27 | #ifndef GCDSharedInstance 28 | #define GCDSharedInstance(block) \ 29 | { \ 30 | static dispatch_once_t predicate = 0; \ 31 | static id sharedInstance = nil; \ 32 | dispatch_once(&predicate, ^{ sharedInstance = block(); }); \ 33 | return sharedInstance; \ 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /GCDObjC/GCDObjC.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCDObjC.h 3 | // GCDObjC 4 | // 5 | // Copyright (c) 2012 Mark Smith. All rights reserved. 6 | // 7 | 8 | #import "GCDMacros.h" 9 | 10 | #import "GCDGroup.h" 11 | #import "GCDQueue.h" 12 | #import "GCDSemaphore.h" 13 | -------------------------------------------------------------------------------- /GCDObjC/GCDQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCDQueue.h 3 | // GCDObjC 4 | // 5 | // Copyright (c) 2012 Mark Smith. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @class GCDGroup; 11 | 12 | @interface GCDQueue : NSObject 13 | 14 | /** 15 | * Returns the underlying dispatch queue object. 16 | * 17 | * @return The dispatch queue object. 18 | */ 19 | @property (strong, readonly, nonatomic) dispatch_queue_t dispatchQueue; 20 | 21 | /** 22 | * Returns the serial dispatch queue associated with the application’s main thread. 23 | * 24 | * @return The main queue. This queue is created automatically on behalf of the main thread before main is called. 25 | * @see dispatch_get_main_queue() 26 | */ 27 | + (GCDQueue *)mainQueue; 28 | 29 | /** 30 | * Returns the default priority global concurrent queue. 31 | * 32 | * @return The queue. 33 | * @see dispatch_get_global_queue() 34 | */ 35 | + (GCDQueue *)globalQueue; 36 | 37 | /** 38 | * Returns the high priority global concurrent queue. 39 | * 40 | * @return The queue. 41 | * @see dispatch_get_global_queue() 42 | */ 43 | + (GCDQueue *)highPriorityGlobalQueue; 44 | 45 | /** 46 | * Returns the low priority global concurrent queue. 47 | * 48 | * @return The queue. 49 | * @see dispatch_get_global_queue() 50 | */ 51 | + (GCDQueue *)lowPriorityGlobalQueue; 52 | 53 | /** 54 | * Returns the background priority global concurrent queue. 55 | * 56 | * @return The queue. 57 | * @see dispatch_get_global_queue() 58 | */ 59 | + (GCDQueue *)backgroundPriorityGlobalQueue; 60 | 61 | /** 62 | * Returns whether the current block is executing on the main queue. 63 | * 64 | * @return YES if so, NO othewise. 65 | */ 66 | + (BOOL)isMainQueue; 67 | 68 | /** 69 | * Initializes a new serial queue. 70 | * 71 | * @return The initialized instance. 72 | * @see dispatch_queue_create() 73 | */ 74 | - (instancetype)init; 75 | 76 | /** 77 | * Initializes a new serial queue. 78 | * 79 | * @return The initialized instance. 80 | * @see dispatch_queue_create() 81 | */ 82 | - (instancetype)initSerial; 83 | 84 | /** 85 | * Initializes a new concurrent queue. 86 | * 87 | * @return The initialized instance. 88 | * @see dispatch_queue_create() 89 | */ 90 | - (instancetype)initConcurrent; 91 | 92 | /** 93 | * The GCDQueue designated initializer. 94 | * 95 | * @param dispatchQueue A dispatch_queue_t object. 96 | * @return The initialized instance. 97 | */ 98 | - (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue; 99 | 100 | /** 101 | * Submits a block for asynchronous execution on the queue. 102 | * 103 | * @param block The block to submit. 104 | * @see dispatch_async() 105 | */ 106 | - (void)queueBlock:(dispatch_block_t)block; 107 | 108 | /** 109 | * Submits a block for asynchronous execution on the queue after a delay. 110 | * 111 | * @param block The block to submit. 112 | * @param afterDelay The delay in seconds. 113 | * @see dispatch_after() 114 | */ 115 | - (void)queueBlock:(dispatch_block_t)block afterDelay:(double)seconds; 116 | 117 | /** 118 | * Submits a block for execution on the queue and waits until it completes. 119 | * 120 | * @param block The block to submit. 121 | * @see dispatch_sync() 122 | */ 123 | - (void)queueAndAwaitBlock:(dispatch_block_t)block; 124 | 125 | /** 126 | * Submits a block for execution on the queue multiple times and waits until all executions complete. 127 | * 128 | * @param block The block to submit. 129 | * @param iterationCount The number of times to execute the block. 130 | * @see dispatch_apply() 131 | */ 132 | - (void)queueAndAwaitBlock:(void (^)(size_t))block iterationCount:(size_t)count; 133 | 134 | /** 135 | * Submits a block for asynchronous execution on the queue and associates it with the group. 136 | * 137 | * @param block The block to submit. 138 | * @param inGroup The group to associate the block with. 139 | * @see dispatch_group_async() 140 | */ 141 | - (void)queueBlock:(dispatch_block_t)block inGroup:(GCDGroup *)group; 142 | 143 | /** 144 | * Schedules a block to be submitted to the queue when a group of previously submitted blocks have completed. 145 | * 146 | * @param block The block to submit when the group completes. 147 | * @param inGroup The group to observe. 148 | * @see dispatch_group_notify() 149 | */ 150 | - (void)queueNotifyBlock:(dispatch_block_t)block inGroup:(GCDGroup *)group; 151 | 152 | /** 153 | * Submits a barrier block for asynchronous execution on the queue. 154 | * 155 | * @param block The barrier block to submit. 156 | * @see dispatch_barrier_async() 157 | */ 158 | - (void)queueBarrierBlock:(dispatch_block_t)block; 159 | 160 | /** 161 | * Submits a barrier block for execution on the queue and waits until it completes. 162 | * 163 | * @param block The barrier block to submit. 164 | * @see dispatch_barrier_sync() 165 | */ 166 | - (void)queueAndAwaitBarrierBlock:(dispatch_block_t)block; 167 | 168 | /** 169 | * Suspends execution of blocks on the queue. 170 | * 171 | * @see dispatch_suspend() 172 | */ 173 | - (void)suspend; 174 | 175 | /** 176 | * Resumes execution of blocks on the queue. 177 | * 178 | * @see dispatch_resume() 179 | */ 180 | - (void)resume; 181 | 182 | /** 183 | * Returns the context associated with a key. 184 | * 185 | * @see dispatch_get_specific() 186 | */ 187 | - (void *)contextForKey:(const void *)key; 188 | 189 | /** 190 | * Sets the context associated with a key. 191 | * 192 | * @see dispatch_queue_set_specific() 193 | */ 194 | - (void)setContext:(void *)context forKey:(const void *)key; 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /GCDObjC/GCDQueue.m: -------------------------------------------------------------------------------- 1 | // 2 | // GCDQueue.m 3 | // GCDObjC 4 | // 5 | // Copyright (c) 2012 Mark Smith. All rights reserved. 6 | // 7 | 8 | #import "GCDGroup.h" 9 | #import "GCDQueue.h" 10 | 11 | static GCDQueue *mainQueue; 12 | static GCDQueue *globalQueue; 13 | static GCDQueue *highPriorityGlobalQueue; 14 | static GCDQueue *lowPriorityGlobalQueue; 15 | static GCDQueue *backgroundPriorityGlobalQueue; 16 | 17 | static uint8_t mainQueueMarker[] = {0}; 18 | 19 | @interface GCDQueue () 20 | @property (strong, readwrite, nonatomic) dispatch_queue_t dispatchQueue; 21 | @end 22 | 23 | @implementation GCDQueue 24 | 25 | #pragma mark Global queue accessors. 26 | 27 | + (GCDQueue *)mainQueue { 28 | return mainQueue; 29 | } 30 | 31 | + (GCDQueue *)globalQueue { 32 | return globalQueue; 33 | } 34 | 35 | + (GCDQueue *)highPriorityGlobalQueue { 36 | return highPriorityGlobalQueue; 37 | } 38 | 39 | + (GCDQueue *)lowPriorityGlobalQueue { 40 | return lowPriorityGlobalQueue; 41 | } 42 | 43 | + (GCDQueue *)backgroundPriorityGlobalQueue { 44 | return backgroundPriorityGlobalQueue; 45 | } 46 | 47 | + (BOOL)isMainQueue { 48 | return dispatch_get_specific(mainQueueMarker) == mainQueueMarker; 49 | } 50 | 51 | #pragma mark Lifecycle. 52 | 53 | + (void)initialize { 54 | if (self == [GCDQueue class]) { 55 | mainQueue = [[GCDQueue alloc] initWithDispatchQueue:dispatch_get_main_queue()]; 56 | globalQueue = [[GCDQueue alloc] initWithDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; 57 | highPriorityGlobalQueue = [[GCDQueue alloc] initWithDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)]; 58 | lowPriorityGlobalQueue = [[GCDQueue alloc] initWithDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)]; 59 | backgroundPriorityGlobalQueue = [[GCDQueue alloc] initWithDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)]; 60 | 61 | [mainQueue setContext:mainQueueMarker forKey:mainQueueMarker]; 62 | } 63 | } 64 | 65 | - (instancetype)init { 66 | return [self initSerial]; 67 | } 68 | 69 | - (instancetype)initSerial { 70 | return [self initWithDispatchQueue:dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL)]; 71 | } 72 | 73 | - (instancetype)initConcurrent { 74 | return [self initWithDispatchQueue:dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT)]; 75 | } 76 | 77 | - (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue { 78 | if ((self = [super init]) != nil) { 79 | self.dispatchQueue = dispatchQueue; 80 | } 81 | 82 | return self; 83 | } 84 | 85 | #pragma mark Public methods. 86 | 87 | - (void)queueBlock:(dispatch_block_t)block { 88 | dispatch_async(self.dispatchQueue, block); 89 | } 90 | 91 | - (void)queueBlock:(dispatch_block_t)block afterDelay:(double)seconds { 92 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (seconds * NSEC_PER_SEC)), self.dispatchQueue, block); 93 | } 94 | 95 | - (void)queueAndAwaitBlock:(dispatch_block_t)block { 96 | dispatch_sync(self.dispatchQueue, block); 97 | } 98 | 99 | - (void)queueAndAwaitBlock:(void (^)(size_t))block iterationCount:(size_t)count { 100 | dispatch_apply(count, self.dispatchQueue, block); 101 | } 102 | 103 | - (void)queueBlock:(dispatch_block_t)block inGroup:(GCDGroup *)group { 104 | dispatch_group_async(group.dispatchGroup, self.dispatchQueue, block); 105 | } 106 | 107 | - (void)queueNotifyBlock:(dispatch_block_t)block inGroup:(GCDGroup *)group { 108 | dispatch_group_notify(group.dispatchGroup, self.dispatchQueue, block); 109 | } 110 | 111 | - (void)queueBarrierBlock:(dispatch_block_t)block { 112 | dispatch_barrier_async(self.dispatchQueue, block); 113 | } 114 | 115 | - (void)queueAndAwaitBarrierBlock:(dispatch_block_t)block { 116 | dispatch_barrier_sync(self.dispatchQueue, block); 117 | } 118 | 119 | - (void)suspend { 120 | dispatch_suspend(self.dispatchQueue); 121 | } 122 | 123 | - (void)resume { 124 | dispatch_resume(self.dispatchQueue); 125 | } 126 | 127 | - (void *)contextForKey:(const void *)key { 128 | return dispatch_get_specific(key); 129 | } 130 | 131 | - (void)setContext:(void *)context forKey:(const void *)key { 132 | dispatch_queue_set_specific(self.dispatchQueue, key, context, NULL); 133 | } 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /GCDObjC/GCDSemaphore.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCDSemaphore.h 3 | // GCDObjC 4 | // 5 | // Copyright (c) 2012 Mark Smith. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface GCDSemaphore : NSObject 11 | 12 | /** 13 | * Returns the underlying dispatch semaphore object. 14 | * 15 | * @return The dispatch semaphore object. 16 | */ 17 | @property (strong, readonly, nonatomic) dispatch_semaphore_t dispatchSemaphore; 18 | 19 | /** 20 | * Initializes a new semaphore with starting value 0. 21 | * 22 | * @return The initialized instance. 23 | * @see dispatch_semaphore_create() 24 | */ 25 | - (instancetype)init; 26 | 27 | /** 28 | * Initializes a new semaphore. 29 | * 30 | * @param value The starting value for the semaphore. 31 | * @return The initialized instance. 32 | * @see dispatch_semaphore_create() 33 | */ 34 | - (instancetype)initWithValue:(long)value; 35 | 36 | /** 37 | * The GCDSemaphore designated initializer. 38 | * 39 | * @param dispatchSemaphore A dispatch_semaphore_t object. 40 | * @return The initialized instance. 41 | * @see dispatch_semaphore_create() 42 | */ 43 | - (instancetype)initWithDispatchSemaphore:(dispatch_semaphore_t)dispatchSemaphore; 44 | 45 | /** 46 | * Signals (increments) the semaphore. 47 | * 48 | * @return YES if a thread is awoken, NO otherwise. 49 | * @see dispatch_semaphore_signal() 50 | */ 51 | - (BOOL)signal; 52 | 53 | /** 54 | * Waits forever for (decrements) the semaphore. 55 | * 56 | * @see dispatch_semaphore_wait() 57 | */ 58 | - (void)wait; 59 | 60 | /** 61 | * Waits for (decrements) the semaphore. 62 | * 63 | * @param seconds The time to wait in seconds. 64 | * @return YES on success, NO if the timeout occurred. 65 | * @see dispatch_semaphore_wait() 66 | */ 67 | - (BOOL)wait:(double)seconds; 68 | 69 | @end -------------------------------------------------------------------------------- /GCDObjC/GCDSemaphore.m: -------------------------------------------------------------------------------- 1 | // 2 | // GCDSemaphore.m 3 | // GCDObjC 4 | // 5 | // Copyright (c) 2012 Mark Smith. All rights reserved. 6 | // 7 | 8 | #import "GCDSemaphore.h" 9 | 10 | @interface GCDSemaphore () 11 | @property (strong, readwrite, nonatomic) dispatch_semaphore_t dispatchSemaphore; 12 | @end 13 | 14 | @implementation GCDSemaphore 15 | 16 | #pragma mark Lifecycle. 17 | 18 | - (instancetype)init { 19 | return [self initWithValue:0]; 20 | } 21 | 22 | - (instancetype)initWithValue:(long)value { 23 | return [self initWithDispatchSemaphore:dispatch_semaphore_create(value)]; 24 | } 25 | 26 | - (instancetype)initWithDispatchSemaphore:(dispatch_semaphore_t)dispatchSemaphore { 27 | if ((self = [super init]) != nil) { 28 | self.dispatchSemaphore = dispatchSemaphore; 29 | } 30 | 31 | return self; 32 | } 33 | 34 | #pragma mark Public methods. 35 | 36 | - (BOOL)signal { 37 | return dispatch_semaphore_signal(self.dispatchSemaphore) != 0; 38 | } 39 | 40 | - (void)wait { 41 | dispatch_semaphore_wait(self.dispatchSemaphore, DISPATCH_TIME_FOREVER); 42 | } 43 | 44 | - (BOOL)wait:(double)seconds { 45 | return dispatch_semaphore_wait(self.dispatchSemaphore, dispatch_time(DISPATCH_TIME_NOW, (seconds * NSEC_PER_SEC))) == 0; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /GCDObjCTests/GCDObjCTests-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 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /GCDObjCTests/GCDObjCTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // GCDQueueTests.m 3 | // GCDObjC 4 | // 5 | // Copyright (c) 2012 Mark Smith. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | 12 | #import "GCDObjC.h" 13 | 14 | @interface GCDObjCTests : XCTestCase 15 | @end 16 | 17 | @implementation GCDObjCTests 18 | 19 | - (void)testMainQueue { 20 | XCTAssertEqual([GCDQueue mainQueue].dispatchQueue, dispatch_get_main_queue()); 21 | 22 | XCTAssertTrue([GCDQueue isMainQueue]); 23 | [[GCDQueue new] queueAndAwaitBlock:^{ XCTAssertFalse([GCDQueue isMainQueue]); }]; 24 | } 25 | 26 | - (void)testGlobalQueues { 27 | XCTAssertEqual([GCDQueue globalQueue].dispatchQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 28 | XCTAssertEqual([GCDQueue highPriorityGlobalQueue].dispatchQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)); 29 | XCTAssertEqual([GCDQueue lowPriorityGlobalQueue].dispatchQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)); 30 | XCTAssertEqual([GCDQueue backgroundPriorityGlobalQueue].dispatchQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)); 31 | } 32 | 33 | - (void)testQueueBlock { 34 | GCDSemaphore *semaphore = [GCDSemaphore new]; 35 | GCDQueue *queue = [GCDQueue new]; 36 | __block int32_t val = 0; 37 | 38 | [queue queueBlock:^{ 39 | OSAtomicIncrement32(&val); 40 | [semaphore signal]; 41 | }]; 42 | 43 | [semaphore wait]; 44 | XCTAssertEqual(val, 1); 45 | } 46 | 47 | - (void)testQueueBlockAfterDelay { 48 | GCDSemaphore *semaphore = [GCDSemaphore new]; 49 | GCDQueue *queue = [GCDQueue new]; 50 | NSDate *then = [NSDate new]; 51 | __block int32_t val = 0; 52 | 53 | [queue queueBlock:^{ 54 | OSAtomicIncrement32(&val); 55 | [semaphore signal]; 56 | } afterDelay:0.5]; 57 | 58 | XCTAssertEqual(val, 0); 59 | [semaphore wait]; 60 | XCTAssertEqual(val, 1); 61 | 62 | NSDate *now = [NSDate new]; 63 | XCTAssertTrue([now timeIntervalSinceDate:then] > 0.4); 64 | XCTAssertTrue([now timeIntervalSinceDate:then] < 0.6); 65 | } 66 | 67 | - (void)testQueueAndAwaitBlock { 68 | GCDQueue *queue = [GCDQueue new]; 69 | __block int32_t val = 0; 70 | 71 | [queue queueAndAwaitBlock:^{ OSAtomicIncrement32(&val); }]; 72 | 73 | XCTAssertEqual(val, 1); 74 | } 75 | 76 | - (void)testQueueAndAwaitBlockIterationCount { 77 | GCDQueue *queue = [[GCDQueue alloc] initConcurrent]; 78 | __block int32_t val = 0; 79 | 80 | [queue queueAndAwaitBlock:^(size_t i){ OSAtomicIncrement32(&val); } iterationCount:100]; 81 | 82 | XCTAssertEqual(val, 100); 83 | } 84 | 85 | - (void)testQueueBlockInGroup { 86 | GCDQueue *queue = [[GCDQueue alloc] initConcurrent]; 87 | GCDGroup *group = [GCDGroup new]; 88 | __block int32_t val = 0; 89 | 90 | for (int i = 0; i < 100; ++i) { 91 | [queue queueBlock:^{ OSAtomicIncrement32(&val); } inGroup:group]; 92 | } 93 | 94 | [group wait]; 95 | XCTAssertEqual(val, 100); 96 | } 97 | 98 | - (void)testQueueNotifyBlockForGroup { 99 | GCDQueue *queue = [[GCDQueue alloc] initConcurrent]; 100 | GCDSemaphore *semaphore = [GCDSemaphore new]; 101 | GCDGroup *group = [GCDGroup new]; 102 | __block int32_t val = 0; 103 | __block int32_t notifyVal = 0; 104 | 105 | for (int i = 0; i < 100; ++i) { 106 | [queue queueBlock:^{ OSAtomicIncrement32(&val); } inGroup:group]; 107 | } 108 | [queue queueNotifyBlock:^{ notifyVal = val; [semaphore signal]; } inGroup:group]; 109 | 110 | [semaphore wait]; 111 | XCTAssertEqual(notifyVal, 100); 112 | } 113 | 114 | - (void)testQueueBarrierBlock { 115 | GCDQueue *queue = [[GCDQueue alloc] initConcurrent]; 116 | GCDSemaphore *semaphore = [GCDSemaphore new]; 117 | __block int32_t val = 0; 118 | __block int32_t barrierVal = 0; 119 | 120 | for (int i = 0; i < 100; ++i) { 121 | [queue queueBlock:^{ OSAtomicIncrement32(&val); }]; 122 | } 123 | [queue queueBarrierBlock:^{ barrierVal = val; [semaphore signal]; }]; 124 | for (int i = 0; i < 100; ++i) { 125 | [queue queueBlock:^{ OSAtomicIncrement32(&val); }]; 126 | } 127 | 128 | [semaphore wait]; 129 | XCTAssertEqual(barrierVal, 100); 130 | } 131 | 132 | - (void)testQueueAndAwaitBarrierBlock { 133 | GCDQueue *queue = [[GCDQueue alloc] initConcurrent]; 134 | __block int32_t val = 0; 135 | 136 | for (int i = 0; i < 100; ++i) { 137 | [queue queueBlock:^{ OSAtomicIncrement32(&val); }]; 138 | } 139 | [queue queueAndAwaitBarrierBlock:^{}]; 140 | XCTAssertEqual(val, 100); 141 | } 142 | 143 | static int onceVal; 144 | 145 | - (void)onceBlock { 146 | GCDExecOnce(^{ ++onceVal; }); 147 | } 148 | 149 | - (void)testExecOnce { 150 | onceVal = 0; 151 | for (int i = 0; i < 100; ++i) { 152 | [self onceBlock]; 153 | } 154 | 155 | XCTAssertEqual(onceVal, 1); 156 | } 157 | 158 | + (instancetype)theTestInstance { 159 | GCDSharedInstance(^{ return [self new]; }); 160 | } 161 | 162 | - (void)testSharedInstance { 163 | XCTAssertTrue([[GCDObjCTests theTestInstance] class] == [self class]); 164 | XCTAssertEqual([GCDObjCTests theTestInstance], [GCDObjCTests theTestInstance]); 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Mark Smith 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GCDObjC 2 | 3 | GCDObjC is an Objective-C wrapper for the most commonly used features of Grand Central Dispatch. It has four main aims: 4 | 5 | * Organize the flat C API into appropriate classes. 6 | * Use intention-revealing names to distinguish between synchronous and asynchronous functions. 7 | * Use more convenient arguments such as time intervals. 8 | * Add convenience methods. 9 | 10 | **A Swift port is at [GCDSwift](https://github.com/mjmsmith/gcdswift).** 11 | 12 | ## Usage 13 | 14 | __GCDObjC__ requires ARC and iOS 6.0. (Prior to 6.0, dispatch objects were not considered Objective-C objects, and therefore required manual memory management.) 15 | 16 | __GCDObjC.h__ is the only header file that needs to be imported. 17 | 18 | For usage examples, see [GCDObjCTests.m](https://github.com/mjmsmith/gcdobjc/blob/master/GCDObjCTests/GCDObjCTests.m). 19 | 20 | Install via CocoaPods: 21 | 22 | ```ruby 23 | pod "GCDObjC" 24 | ``` 25 | 26 | ## GCDQueue 27 | 28 | Queues are implemented in the __GCDQueue__ class. 29 | 30 | * convenience accessors for global queues 31 | 32 | ```objc 33 | + (GCDQueue *)mainQueue; 34 | + (GCDQueue *)globalQueue; 35 | + (GCDQueue *)highPriorityGlobalQueue; 36 | + (GCDQueue *)lowPriorityGlobalQueue; 37 | + (GCDQueue *)backgroundPriorityGlobalQueue; 38 | ``` 39 | 40 | * testing the current execution context 41 | 42 | ```objc 43 | + (BOOL)isMainQueue; 44 | ``` 45 | 46 | * creating serial and concurrent queues 47 | 48 | ```objc 49 | - (instancetype)initSerial; 50 | - (instancetype)initConcurrent; 51 | ``` 52 | 53 | * queueing blocks for asynchronous execution 54 | 55 | ```objc 56 | - (void)queueBlock:(dispatch_block_t)block; 57 | - (void)queueBlock:(dispatch_block_t)block afterDelay:(double)seconds; 58 | - (void)queueBlock:(dispatch_block_t)block inGroup:(GCDGroup *)group; 59 | ``` 60 | 61 | * queueing blocks for synchronous execution 62 | 63 | ```objc 64 | - (void)queueAndAwaitBlock:(dispatch_block_t)block; 65 | - (void)queueAndAwaitBlock:(void (^)(size_t))block iterationCount:(size_t)count; 66 | ``` 67 | 68 | * queueing barrier blocks for synchronous or asynchronous execution 69 | 70 | ```objc 71 | - (void)queueBarrierBlock:(dispatch_block_t)block; 72 | - (void)queueAndAwaitBarrierBlock:(dispatch_block_t)block; 73 | ``` 74 | 75 | * queueing notify blocks on groups 76 | 77 | ```objc 78 | - (void)queueNotifyBlock:(dispatch_block_t)block inGroup:(GCDGroup *)group; 79 | ``` 80 | 81 | * suspending and resuming a queue 82 | 83 | ```objc 84 | - (void)suspend; 85 | - (void)resume; 86 | ``` 87 | 88 | * associating context data with a key 89 | 90 | ```objc 91 | - (void *)contextForKey:(const void *)key; 92 | - (void)setContext:(void *)context forKey:(const void *)key; 93 | ``` 94 | 95 | ## GCDSemaphore 96 | 97 | Semaphores are implemented in the __GCDSemaphore__ class. 98 | 99 | * creating semaphores 100 | 101 | ```objc 102 | - (instancetype)init; 103 | - (instancetype)initWithValue:(long)value; 104 | ``` 105 | 106 | * signaling and waiting on a semaphore 107 | 108 | ```objc 109 | - (BOOL)signal; 110 | - (void)wait; 111 | - (BOOL)wait:(double)seconds; 112 | ``` 113 | 114 | ## GCDGroup 115 | 116 | Groups are implemented in the __GCDGroup__ class. 117 | 118 | * creating groups 119 | 120 | ```objc 121 | - (instancetype)init; 122 | ``` 123 | 124 | * entering and leaving a group 125 | 126 | ```objc 127 | - (void)enter; 128 | - (void)leave; 129 | ``` 130 | 131 | * waiting on completion of a group 132 | 133 | ```objc 134 | - (void)wait; 135 | - (BOOL)wait:(double)seconds; 136 | ``` 137 | 138 | ## Macros 139 | 140 | Two macros are provided for wrapping __dispatch_once()__ calls. 141 | 142 | * executing a block only once: __GCDExecOnce(block)__ 143 | 144 | ```objc 145 | for (int i = 0; i < 10; ++i) { 146 | GCDExecOnce(^{ NSLog(@"This will only be logged once."); }); 147 | } 148 | ``` 149 | 150 | * creating a singleton instance of a class: __GCDSharedInstance(block)__ 151 | 152 | ```objc 153 | + (instancetype)sharedInstance { 154 | GCDSharedInstance(^{ return [self new]; }); 155 | } 156 | ``` 157 | 158 | The block supplied to __GCDSharedInstance()__ must return an instance of the desired class. 159 | --------------------------------------------------------------------------------