├── .gitignore ├── Atomic-OSX └── Info.plist ├── Atomic.podspec ├── Atomic.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── Atomic.xcscheme ├── Atomic.xcworkspace └── contents.xcworkspacedata ├── Atomic ├── Atomic.h ├── Atomic.swift ├── Info.plist └── Lock.swift ├── AtomicTests ├── AtomicTests.swift └── Info.plist ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | -------------------------------------------------------------------------------- /Atomic-OSX/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Atomic.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'Atomic' 3 | s.version = '1.0.3' 4 | s.license = 'MIT' 5 | s.summary = 'Atomic is a fast, safe way to make values atomic (thread-safe).' 6 | s.homepage = 'https://github.com/Adlai-Holler/Atomic' 7 | s.social_media_url = 'http://twitter.com/adlaih' 8 | s.authors = { 'Adlai Holler' => 'him@adlai.io' } 9 | s.source = { :git => 'https://github.com/Adlai-Holler/Atomic.git', :tag => 'v1.0.3' } 10 | 11 | s.ios.deployment_target = '8.0' 12 | s.osx.deployment_target = '10.10' 13 | 14 | s.source_files = 'Atomic/*.swift' 15 | 16 | s.requires_arc = true 17 | end 18 | -------------------------------------------------------------------------------- /Atomic.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | CC60355C1C136EE4003ED664 /* Atomic.h in Headers */ = {isa = PBXBuildFile; fileRef = CC60355B1C136EE4003ED664 /* Atomic.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | CC6035731C136EF2003ED664 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC6035721C136EF2003ED664 /* Atomic.swift */; }; 12 | CC649D681C14D6840085ADDE /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC6035721C136EF2003ED664 /* Atomic.swift */; }; 13 | CC649D701C14D8E90085ADDE /* AtomicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC649D6F1C14D8E90085ADDE /* AtomicTests.swift */; }; 14 | CC649D721C14D8E90085ADDE /* Atomic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CC649D501C14D6500085ADDE /* Atomic.framework */; }; 15 | CCDAC6C31C5F2D3700255715 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCDAC6C21C5F2D3700255715 /* Lock.swift */; }; 16 | CCDAC6C41C5F2ECC00255715 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCDAC6C21C5F2D3700255715 /* Lock.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | CC649D731C14D8E90085ADDE /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = CC60354F1C136EE4003ED664 /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = CC649D4F1C14D6500085ADDE; 25 | remoteInfo = "Atomic-OSX"; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | CC6035581C136EE4003ED664 /* Atomic.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Atomic.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | CC60355B1C136EE4003ED664 /* Atomic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Atomic.h; sourceTree = ""; }; 32 | CC60355D1C136EE4003ED664 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | CC6035721C136EF2003ED664 /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; 34 | CC649D501C14D6500085ADDE /* Atomic.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Atomic.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | CC649D6D1C14D8E90085ADDE /* AtomicTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AtomicTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | CC649D6F1C14D8E90085ADDE /* AtomicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicTests.swift; sourceTree = ""; }; 37 | CC649D711C14D8E90085ADDE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | CCDAC6C21C5F2D3700255715 /* Lock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lock.swift; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | CC6035541C136EE4003ED664 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | CC649D4C1C14D6500085ADDE /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | CC649D6A1C14D8E90085ADDE /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | CC649D721C14D8E90085ADDE /* Atomic.framework in Frameworks */, 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXFrameworksBuildPhase section */ 65 | 66 | /* Begin PBXGroup section */ 67 | CC60354E1C136EE4003ED664 = { 68 | isa = PBXGroup; 69 | children = ( 70 | CC60355A1C136EE4003ED664 /* Atomic */, 71 | CC649D6E1C14D8E90085ADDE /* AtomicTests */, 72 | CC6035591C136EE4003ED664 /* Products */, 73 | ); 74 | sourceTree = ""; 75 | }; 76 | CC6035591C136EE4003ED664 /* Products */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | CC6035581C136EE4003ED664 /* Atomic.framework */, 80 | CC649D501C14D6500085ADDE /* Atomic.framework */, 81 | CC649D6D1C14D8E90085ADDE /* AtomicTests.xctest */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | CC60355A1C136EE4003ED664 /* Atomic */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | CC60355B1C136EE4003ED664 /* Atomic.h */, 90 | CC6035721C136EF2003ED664 /* Atomic.swift */, 91 | CCDAC6C21C5F2D3700255715 /* Lock.swift */, 92 | CC60355D1C136EE4003ED664 /* Info.plist */, 93 | ); 94 | path = Atomic; 95 | sourceTree = ""; 96 | }; 97 | CC649D6E1C14D8E90085ADDE /* AtomicTests */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | CC649D6F1C14D8E90085ADDE /* AtomicTests.swift */, 101 | CC649D711C14D8E90085ADDE /* Info.plist */, 102 | ); 103 | path = AtomicTests; 104 | sourceTree = ""; 105 | }; 106 | /* End PBXGroup section */ 107 | 108 | /* Begin PBXHeadersBuildPhase section */ 109 | CC6035551C136EE4003ED664 /* Headers */ = { 110 | isa = PBXHeadersBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | CC60355C1C136EE4003ED664 /* Atomic.h in Headers */, 114 | ); 115 | runOnlyForDeploymentPostprocessing = 0; 116 | }; 117 | CC649D4D1C14D6500085ADDE /* Headers */ = { 118 | isa = PBXHeadersBuildPhase; 119 | buildActionMask = 2147483647; 120 | files = ( 121 | ); 122 | runOnlyForDeploymentPostprocessing = 0; 123 | }; 124 | /* End PBXHeadersBuildPhase section */ 125 | 126 | /* Begin PBXNativeTarget section */ 127 | CC6035571C136EE4003ED664 /* Atomic */ = { 128 | isa = PBXNativeTarget; 129 | buildConfigurationList = CC60356C1C136EE4003ED664 /* Build configuration list for PBXNativeTarget "Atomic" */; 130 | buildPhases = ( 131 | CC6035531C136EE4003ED664 /* Sources */, 132 | CC6035541C136EE4003ED664 /* Frameworks */, 133 | CC6035551C136EE4003ED664 /* Headers */, 134 | CC6035561C136EE4003ED664 /* Resources */, 135 | ); 136 | buildRules = ( 137 | ); 138 | dependencies = ( 139 | ); 140 | name = Atomic; 141 | productName = Atomic; 142 | productReference = CC6035581C136EE4003ED664 /* Atomic.framework */; 143 | productType = "com.apple.product-type.framework"; 144 | }; 145 | CC649D4F1C14D6500085ADDE /* Atomic-OSX */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = CC649D651C14D6500085ADDE /* Build configuration list for PBXNativeTarget "Atomic-OSX" */; 148 | buildPhases = ( 149 | CC649D4B1C14D6500085ADDE /* Sources */, 150 | CC649D4C1C14D6500085ADDE /* Frameworks */, 151 | CC649D4D1C14D6500085ADDE /* Headers */, 152 | CC649D4E1C14D6500085ADDE /* Resources */, 153 | ); 154 | buildRules = ( 155 | ); 156 | dependencies = ( 157 | ); 158 | name = "Atomic-OSX"; 159 | productName = "Atomic-OSX"; 160 | productReference = CC649D501C14D6500085ADDE /* Atomic.framework */; 161 | productType = "com.apple.product-type.framework"; 162 | }; 163 | CC649D6C1C14D8E90085ADDE /* AtomicTests */ = { 164 | isa = PBXNativeTarget; 165 | buildConfigurationList = CC649D751C14D8E90085ADDE /* Build configuration list for PBXNativeTarget "AtomicTests" */; 166 | buildPhases = ( 167 | CC649D691C14D8E90085ADDE /* Sources */, 168 | CC649D6A1C14D8E90085ADDE /* Frameworks */, 169 | CC649D6B1C14D8E90085ADDE /* Resources */, 170 | ); 171 | buildRules = ( 172 | ); 173 | dependencies = ( 174 | CC649D741C14D8E90085ADDE /* PBXTargetDependency */, 175 | ); 176 | name = AtomicTests; 177 | productName = AtomicTests; 178 | productReference = CC649D6D1C14D8E90085ADDE /* AtomicTests.xctest */; 179 | productType = "com.apple.product-type.bundle.unit-test"; 180 | }; 181 | /* End PBXNativeTarget section */ 182 | 183 | /* Begin PBXProject section */ 184 | CC60354F1C136EE4003ED664 /* Project object */ = { 185 | isa = PBXProject; 186 | attributes = { 187 | LastSwiftUpdateCheck = 0710; 188 | LastUpgradeCheck = 0710; 189 | ORGANIZATIONNAME = "Adlai Holler"; 190 | TargetAttributes = { 191 | CC6035571C136EE4003ED664 = { 192 | CreatedOnToolsVersion = 7.1.1; 193 | }; 194 | CC649D4F1C14D6500085ADDE = { 195 | CreatedOnToolsVersion = 7.1.1; 196 | }; 197 | CC649D6C1C14D8E90085ADDE = { 198 | CreatedOnToolsVersion = 7.1.1; 199 | }; 200 | }; 201 | }; 202 | buildConfigurationList = CC6035521C136EE4003ED664 /* Build configuration list for PBXProject "Atomic" */; 203 | compatibilityVersion = "Xcode 3.2"; 204 | developmentRegion = English; 205 | hasScannedForEncodings = 0; 206 | knownRegions = ( 207 | en, 208 | ); 209 | mainGroup = CC60354E1C136EE4003ED664; 210 | productRefGroup = CC6035591C136EE4003ED664 /* Products */; 211 | projectDirPath = ""; 212 | projectRoot = ""; 213 | targets = ( 214 | CC6035571C136EE4003ED664 /* Atomic */, 215 | CC649D4F1C14D6500085ADDE /* Atomic-OSX */, 216 | CC649D6C1C14D8E90085ADDE /* AtomicTests */, 217 | ); 218 | }; 219 | /* End PBXProject section */ 220 | 221 | /* Begin PBXResourcesBuildPhase section */ 222 | CC6035561C136EE4003ED664 /* Resources */ = { 223 | isa = PBXResourcesBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | CC649D4E1C14D6500085ADDE /* Resources */ = { 230 | isa = PBXResourcesBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | CC649D6B1C14D8E90085ADDE /* Resources */ = { 237 | isa = PBXResourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | /* End PBXResourcesBuildPhase section */ 244 | 245 | /* Begin PBXSourcesBuildPhase section */ 246 | CC6035531C136EE4003ED664 /* Sources */ = { 247 | isa = PBXSourcesBuildPhase; 248 | buildActionMask = 2147483647; 249 | files = ( 250 | CCDAC6C31C5F2D3700255715 /* Lock.swift in Sources */, 251 | CC6035731C136EF2003ED664 /* Atomic.swift in Sources */, 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | CC649D4B1C14D6500085ADDE /* Sources */ = { 256 | isa = PBXSourcesBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | CCDAC6C41C5F2ECC00255715 /* Lock.swift in Sources */, 260 | CC649D681C14D6840085ADDE /* Atomic.swift in Sources */, 261 | ); 262 | runOnlyForDeploymentPostprocessing = 0; 263 | }; 264 | CC649D691C14D8E90085ADDE /* Sources */ = { 265 | isa = PBXSourcesBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | CC649D701C14D8E90085ADDE /* AtomicTests.swift in Sources */, 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | }; 272 | /* End PBXSourcesBuildPhase section */ 273 | 274 | /* Begin PBXTargetDependency section */ 275 | CC649D741C14D8E90085ADDE /* PBXTargetDependency */ = { 276 | isa = PBXTargetDependency; 277 | target = CC649D4F1C14D6500085ADDE /* Atomic-OSX */; 278 | targetProxy = CC649D731C14D8E90085ADDE /* PBXContainerItemProxy */; 279 | }; 280 | /* End PBXTargetDependency section */ 281 | 282 | /* Begin XCBuildConfiguration section */ 283 | CC60356A1C136EE4003ED664 /* Debug */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | ALWAYS_SEARCH_USER_PATHS = NO; 287 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 288 | CLANG_CXX_LIBRARY = "libc++"; 289 | CLANG_ENABLE_MODULES = YES; 290 | CLANG_ENABLE_OBJC_ARC = YES; 291 | CLANG_WARN_BOOL_CONVERSION = YES; 292 | CLANG_WARN_CONSTANT_CONVERSION = YES; 293 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 294 | CLANG_WARN_EMPTY_BODY = YES; 295 | CLANG_WARN_ENUM_CONVERSION = YES; 296 | CLANG_WARN_INT_CONVERSION = YES; 297 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 298 | CLANG_WARN_UNREACHABLE_CODE = YES; 299 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 300 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 301 | COPY_PHASE_STRIP = NO; 302 | CURRENT_PROJECT_VERSION = 1; 303 | DEBUG_INFORMATION_FORMAT = dwarf; 304 | ENABLE_STRICT_OBJC_MSGSEND = YES; 305 | ENABLE_TESTABILITY = YES; 306 | GCC_C_LANGUAGE_STANDARD = gnu99; 307 | GCC_DYNAMIC_NO_PIC = NO; 308 | GCC_NO_COMMON_BLOCKS = YES; 309 | GCC_OPTIMIZATION_LEVEL = 0; 310 | GCC_PREPROCESSOR_DEFINITIONS = ( 311 | "DEBUG=1", 312 | "$(inherited)", 313 | ); 314 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 315 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 316 | GCC_WARN_UNDECLARED_SELECTOR = YES; 317 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 318 | GCC_WARN_UNUSED_FUNCTION = YES; 319 | GCC_WARN_UNUSED_VARIABLE = YES; 320 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 321 | MTL_ENABLE_DEBUG_INFO = YES; 322 | ONLY_ACTIVE_ARCH = YES; 323 | SDKROOT = iphoneos; 324 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 325 | TARGETED_DEVICE_FAMILY = "1,2"; 326 | VERSIONING_SYSTEM = "apple-generic"; 327 | VERSION_INFO_PREFIX = ""; 328 | }; 329 | name = Debug; 330 | }; 331 | CC60356B1C136EE4003ED664 /* Release */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | ALWAYS_SEARCH_USER_PATHS = NO; 335 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 336 | CLANG_CXX_LIBRARY = "libc++"; 337 | CLANG_ENABLE_MODULES = YES; 338 | CLANG_ENABLE_OBJC_ARC = YES; 339 | CLANG_WARN_BOOL_CONVERSION = YES; 340 | CLANG_WARN_CONSTANT_CONVERSION = YES; 341 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 342 | CLANG_WARN_EMPTY_BODY = YES; 343 | CLANG_WARN_ENUM_CONVERSION = YES; 344 | CLANG_WARN_INT_CONVERSION = YES; 345 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 346 | CLANG_WARN_UNREACHABLE_CODE = YES; 347 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 348 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 349 | COPY_PHASE_STRIP = NO; 350 | CURRENT_PROJECT_VERSION = 1; 351 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 352 | ENABLE_NS_ASSERTIONS = NO; 353 | ENABLE_STRICT_OBJC_MSGSEND = YES; 354 | GCC_C_LANGUAGE_STANDARD = gnu99; 355 | GCC_NO_COMMON_BLOCKS = YES; 356 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 357 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 358 | GCC_WARN_UNDECLARED_SELECTOR = YES; 359 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 360 | GCC_WARN_UNUSED_FUNCTION = YES; 361 | GCC_WARN_UNUSED_VARIABLE = YES; 362 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 363 | MTL_ENABLE_DEBUG_INFO = NO; 364 | SDKROOT = iphoneos; 365 | TARGETED_DEVICE_FAMILY = "1,2"; 366 | VALIDATE_PRODUCT = YES; 367 | VERSIONING_SYSTEM = "apple-generic"; 368 | VERSION_INFO_PREFIX = ""; 369 | }; 370 | name = Release; 371 | }; 372 | CC60356D1C136EE4003ED664 /* Debug */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | CLANG_ENABLE_MODULES = YES; 376 | DEFINES_MODULE = YES; 377 | DYLIB_COMPATIBILITY_VERSION = 1; 378 | DYLIB_CURRENT_VERSION = 1; 379 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 380 | INFOPLIST_FILE = Atomic/Info.plist; 381 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 382 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 383 | PRODUCT_BUNDLE_IDENTIFIER = adlai.Atomic; 384 | PRODUCT_NAME = "$(TARGET_NAME)"; 385 | SKIP_INSTALL = YES; 386 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 387 | }; 388 | name = Debug; 389 | }; 390 | CC60356E1C136EE4003ED664 /* Release */ = { 391 | isa = XCBuildConfiguration; 392 | buildSettings = { 393 | CLANG_ENABLE_MODULES = YES; 394 | DEFINES_MODULE = YES; 395 | DYLIB_COMPATIBILITY_VERSION = 1; 396 | DYLIB_CURRENT_VERSION = 1; 397 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 398 | INFOPLIST_FILE = Atomic/Info.plist; 399 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 400 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 401 | PRODUCT_BUNDLE_IDENTIFIER = adlai.Atomic; 402 | PRODUCT_NAME = "$(TARGET_NAME)"; 403 | SKIP_INSTALL = YES; 404 | }; 405 | name = Release; 406 | }; 407 | CC649D611C14D6500085ADDE /* Debug */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | CODE_SIGN_IDENTITY = "-"; 411 | COMBINE_HIDPI_IMAGES = YES; 412 | DEFINES_MODULE = YES; 413 | DYLIB_COMPATIBILITY_VERSION = 1; 414 | DYLIB_CURRENT_VERSION = 1; 415 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 416 | FRAMEWORK_VERSION = A; 417 | INFOPLIST_FILE = "Atomic-OSX/Info.plist"; 418 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 419 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 420 | MACOSX_DEPLOYMENT_TARGET = 10.11; 421 | PRODUCT_BUNDLE_IDENTIFIER = "adlai.Atomic-OSX"; 422 | PRODUCT_NAME = "$(PROJECT_NAME)"; 423 | SDKROOT = macosx; 424 | SKIP_INSTALL = YES; 425 | }; 426 | name = Debug; 427 | }; 428 | CC649D621C14D6500085ADDE /* Release */ = { 429 | isa = XCBuildConfiguration; 430 | buildSettings = { 431 | CODE_SIGN_IDENTITY = "-"; 432 | COMBINE_HIDPI_IMAGES = YES; 433 | DEFINES_MODULE = YES; 434 | DYLIB_COMPATIBILITY_VERSION = 1; 435 | DYLIB_CURRENT_VERSION = 1; 436 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 437 | FRAMEWORK_VERSION = A; 438 | INFOPLIST_FILE = "Atomic-OSX/Info.plist"; 439 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 440 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 441 | MACOSX_DEPLOYMENT_TARGET = 10.11; 442 | PRODUCT_BUNDLE_IDENTIFIER = "adlai.Atomic-OSX"; 443 | PRODUCT_NAME = "$(PROJECT_NAME)"; 444 | SDKROOT = macosx; 445 | SKIP_INSTALL = YES; 446 | }; 447 | name = Release; 448 | }; 449 | CC649D761C14D8E90085ADDE /* Debug */ = { 450 | isa = XCBuildConfiguration; 451 | buildSettings = { 452 | CODE_SIGN_IDENTITY = "-"; 453 | COMBINE_HIDPI_IMAGES = YES; 454 | INFOPLIST_FILE = AtomicTests/Info.plist; 455 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 456 | MACOSX_DEPLOYMENT_TARGET = 10.11; 457 | PRODUCT_BUNDLE_IDENTIFIER = adlai.AtomicTests; 458 | PRODUCT_NAME = "$(TARGET_NAME)"; 459 | SDKROOT = macosx; 460 | }; 461 | name = Debug; 462 | }; 463 | CC649D771C14D8E90085ADDE /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | CODE_SIGN_IDENTITY = "-"; 467 | COMBINE_HIDPI_IMAGES = YES; 468 | INFOPLIST_FILE = AtomicTests/Info.plist; 469 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 470 | MACOSX_DEPLOYMENT_TARGET = 10.11; 471 | PRODUCT_BUNDLE_IDENTIFIER = adlai.AtomicTests; 472 | PRODUCT_NAME = "$(TARGET_NAME)"; 473 | SDKROOT = macosx; 474 | }; 475 | name = Release; 476 | }; 477 | /* End XCBuildConfiguration section */ 478 | 479 | /* Begin XCConfigurationList section */ 480 | CC6035521C136EE4003ED664 /* Build configuration list for PBXProject "Atomic" */ = { 481 | isa = XCConfigurationList; 482 | buildConfigurations = ( 483 | CC60356A1C136EE4003ED664 /* Debug */, 484 | CC60356B1C136EE4003ED664 /* Release */, 485 | ); 486 | defaultConfigurationIsVisible = 0; 487 | defaultConfigurationName = Release; 488 | }; 489 | CC60356C1C136EE4003ED664 /* Build configuration list for PBXNativeTarget "Atomic" */ = { 490 | isa = XCConfigurationList; 491 | buildConfigurations = ( 492 | CC60356D1C136EE4003ED664 /* Debug */, 493 | CC60356E1C136EE4003ED664 /* Release */, 494 | ); 495 | defaultConfigurationIsVisible = 0; 496 | defaultConfigurationName = Release; 497 | }; 498 | CC649D651C14D6500085ADDE /* Build configuration list for PBXNativeTarget "Atomic-OSX" */ = { 499 | isa = XCConfigurationList; 500 | buildConfigurations = ( 501 | CC649D611C14D6500085ADDE /* Debug */, 502 | CC649D621C14D6500085ADDE /* Release */, 503 | ); 504 | defaultConfigurationIsVisible = 0; 505 | defaultConfigurationName = Release; 506 | }; 507 | CC649D751C14D8E90085ADDE /* Build configuration list for PBXNativeTarget "AtomicTests" */ = { 508 | isa = XCConfigurationList; 509 | buildConfigurations = ( 510 | CC649D761C14D8E90085ADDE /* Debug */, 511 | CC649D771C14D8E90085ADDE /* Release */, 512 | ); 513 | defaultConfigurationIsVisible = 0; 514 | defaultConfigurationName = Release; 515 | }; 516 | /* End XCConfigurationList section */ 517 | }; 518 | rootObject = CC60354F1C136EE4003ED664 /* Project object */; 519 | } 520 | -------------------------------------------------------------------------------- /Atomic.xcodeproj/xcshareddata/xcschemes/Atomic.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 55 | 61 | 62 | 63 | 64 | 65 | 66 | 72 | 73 | 79 | 80 | 81 | 82 | 84 | 85 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Atomic.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Atomic/Atomic.h: -------------------------------------------------------------------------------- 1 | // 2 | // Atomic.h 3 | // Atomic 4 | // 5 | // Created by Adlai Holler on 12/5/15. 6 | // Copyright © 2015 Adlai Holler. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Atomic. 12 | FOUNDATION_EXPORT double AtomicVersionNumber; 13 | 14 | //! Project version string for Atomic. 15 | FOUNDATION_EXPORT const unsigned char AtomicVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Atomic/Atomic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Atomic.swift 3 | // Atomic 4 | // 5 | // Adapted from Atomic.swift in ReactiveCocoa. 6 | // Original file is by Justin Spahr-Summers 2014-06-10. 7 | // 8 | 9 | import Foundation 10 | 11 | /// An atomic variable. 12 | public final class Atomic { 13 | internal let lock = Lock() 14 | internal var _value: Value 15 | 16 | /// Atomically gets or sets the value of the variable. 17 | public var value: Value { 18 | get { 19 | return lock.withCriticalScope { 20 | _value 21 | } 22 | } 23 | 24 | set(newValue) { 25 | lock.withCriticalScope { 26 | _value = newValue 27 | } 28 | } 29 | } 30 | 31 | /// Initializes the variable with the given initial value. 32 | public init(_ value: Value) { 33 | _value = value 34 | } 35 | 36 | 37 | /// Atomically replaces the contents of the variable. 38 | /// 39 | /// Returns the old value. 40 | public func swap(newValue: Value) -> Value { 41 | return modify { _ in newValue } 42 | } 43 | 44 | /// Atomically modifies the variable. 45 | /// 46 | /// Returns the old value. 47 | public func modify(@noescape action: (Value) throws -> Value) rethrows -> Value { 48 | return try lock.withCriticalScope { 49 | let oldValue = _value 50 | _value = try action(_value) 51 | return oldValue 52 | } 53 | } 54 | 55 | /// Atomically performs an arbitrary action using the current value of the 56 | /// variable. 57 | /// 58 | /// Returns the result of the action. 59 | public func withValue(@noescape action: (Value) throws -> Result) rethrows -> Result { 60 | return try lock.withCriticalScope { 61 | try action(_value) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Atomic/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Atomic/Lock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Lock.swift 3 | // Atomic 4 | // 5 | // Created by Adlai Holler on 1/31/16. 6 | // Copyright © 2016 Adlai Holler. All rights reserved. 7 | // 8 | 9 | import Darwin 10 | 11 | final public class Lock { 12 | internal var _lock = pthread_mutex_t() 13 | 14 | /// Initializes the variable with the given initial value. 15 | public init() { 16 | let result = pthread_mutex_init(&_lock, nil) 17 | assert(result == 0, "Failed to init mutex in \(self)") 18 | } 19 | 20 | public func lock() { 21 | let result = pthread_mutex_lock(&_lock) 22 | assert(result == 0, "Failed to lock mutex in \(self)") 23 | } 24 | 25 | public func tryLock() -> Int32 { 26 | return pthread_mutex_trylock(&_lock) 27 | } 28 | 29 | public func unlock() { 30 | let result = pthread_mutex_unlock(&_lock) 31 | assert(result == 0, "Failed to unlock mutex in \(self)") 32 | } 33 | 34 | deinit { 35 | let result = pthread_mutex_destroy(&_lock) 36 | assert(result == 0, "Failed to destroy mutex in \(self)") 37 | } 38 | 39 | } 40 | 41 | extension Lock { 42 | public func withCriticalScope(@noescape body: () throws -> Result) rethrows -> Result { 43 | lock() 44 | defer { unlock() } 45 | return try body() 46 | } 47 | } -------------------------------------------------------------------------------- /AtomicTests/AtomicTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AtomicTests.swift 3 | // AtomicTests 4 | // 5 | // Created by Adlai Holler on 12/5/15. 6 | // Copyright © 2015 Adlai Holler. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Atomic 11 | 12 | class AtomicTests: XCTestCase { 13 | 14 | func testModify() { 15 | let atomic = Atomic(0) 16 | atomic.modify { $0 + 7 } 17 | XCTAssertEqual(atomic._value, 7) 18 | } 19 | 20 | func testWithValue() { 21 | let atomic = Atomic(0) 22 | let result = atomic.withValue { $0 + 7 } 23 | XCTAssertEqual(atomic._value, 0) 24 | XCTAssertEqual(result, 7) 25 | } 26 | 27 | func testSetProperty() { 28 | let atomic = Atomic(0) 29 | atomic.value = 25 30 | XCTAssertEqual(atomic._value, 25) 31 | } 32 | 33 | func testGetProperty() { 34 | let atomic = Atomic(0) 35 | atomic._value = 25 36 | XCTAssertEqual(atomic.value, 25) 37 | } 38 | 39 | func testSwap() { 40 | let atomic = Atomic(1) 41 | let oldValue = atomic.swap(25) 42 | XCTAssertEqual(oldValue, 1) 43 | XCTAssertEqual(atomic._value, 25) 44 | } 45 | 46 | func testRethrowFromWithValue() { 47 | let atomic = Atomic(10) 48 | var didCatch = false 49 | do { 50 | try atomic.withValue { value in 51 | throw NSError(domain: NSCocoaErrorDomain, code: value, userInfo: nil) 52 | } 53 | XCTFail() 54 | } catch let error as NSError { 55 | didCatch = true 56 | XCTAssertEqual(error, NSError(domain: NSCocoaErrorDomain, code: 10, userInfo: nil)) 57 | } 58 | if atomic.lock.tryLock() == 0 { 59 | atomic.lock.unlock() 60 | } else { 61 | XCTFail() 62 | } 63 | XCTAssert(didCatch) 64 | } 65 | 66 | func testRethrowFromModify() { 67 | let atomic = Atomic(10) 68 | var didCatch = false 69 | do { 70 | try atomic.modify { value in 71 | throw NSError(domain: NSCocoaErrorDomain, code: value, userInfo: nil) 72 | } 73 | XCTFail() 74 | } catch let error as NSError { 75 | didCatch = true 76 | XCTAssertEqual(error, NSError(domain: NSCocoaErrorDomain, code: 10, userInfo: nil)) 77 | } 78 | if atomic.lock.tryLock() == 0 { 79 | atomic.lock.unlock() 80 | } else { 81 | XCTFail() 82 | } 83 | XCTAssert(didCatch) 84 | } 85 | 86 | func testHighlyContestedLocking() { 87 | let contestedAtomic = Atomic(0) 88 | let concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 89 | let dispatchGroup = dispatch_group_create() 90 | let count = 100_000 91 | for _ in 0.. 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Adlai Holler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Atomic 2 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![CocoaPods compatible](https://img.shields.io/cocoapods/v/Atomic.svg)](https://cocoapods.org) [![CocoaPods compatible](https://img.shields.io/cocoapods/p/Atomic.svg)](https://cocoapods.org) 3 | 4 | Atomic is a fast, safe class for making values thread-safe in Swift. It is backed by `pthread_mutex_lock` which is the fastest, most-efficient locking mechanism available. 5 | 6 | ### Installation 7 | 8 | - Using [CocoaPods](https://cocoapods.org) by adding `pod Atomic` to your Podfile 9 | - Using [Carthage](https://github.com/Carthage/Carthage) by adding `github "Adlai-Holler/Atomic"` to your Cartfile. 10 | 11 | ### How to Use 12 | 13 | ```swift 14 | /// This class is completely thread-safe (yay!). 15 | final class MyCache { 16 | private let entries: Atomic<[String: Value]> = Atomic([:]) 17 | 18 | func valueForKey(key: String) -> Value? { 19 | return entries.withValue { $0[key] } 20 | } 21 | 22 | func setValue(value: Value, forKey: Key) { 23 | entries.modify { (var dict) in 24 | dict[key] = value 25 | return dict 26 | } 27 | } 28 | 29 | func clear() { 30 | entries.value = [:] 31 | } 32 | 33 | func copy() -> [String: Value] { 34 | return entries.value 35 | } 36 | } 37 | ``` 38 | 39 | #### Another Example 40 | 41 | ```swift 42 | /// Thread-safe manager for the `networkActivityIndicator` on iOS. 43 | final class NetworkActivityIndicatorManager { 44 | static let shared = NetworkActivityIndicatorManager() 45 | 46 | private let count = Atomic(0) 47 | 48 | func incrementActivityCount() { 49 | let oldValue = count.modify { $0 + 1 } 50 | if oldValue == 0 { 51 | updateUI(true) 52 | } 53 | } 54 | 55 | func decrementActivityCount() { 56 | let oldValue = count.modify { $0 - 1 } 57 | if oldValue == 1 { 58 | updateUI(false) 59 | } 60 | } 61 | 62 | private func updateUI(on: Bool) { 63 | dispatch_async(dispatch_get_main_queue()) { 64 | UIApplication.sharedApplication().networkActivityIndicatorVisible = true 65 | } 66 | } 67 | } 68 | ``` 69 | 70 | ### Features 71 | 72 | - Safe. No need to remember to unlock. 73 | - Fast. `pthread_mutex_lock` is faster than `NSLock` and more efficient than `OSSpinLock`. 74 | - Modern. You can safely `throw` errors inside its methods, uses `@noescape` and generics to make your code as clean as possible. 75 | - Tested. This thing is tested like crazy, including accessing it concurrently from 100,000 operations! 76 | 77 | ### Attribution 78 | 79 | The original version of `Atomic.swift` was written by the [ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa) contributors. 80 | --------------------------------------------------------------------------------