{"id":24352599,"url":"https://github.com/flowduino/threadsafeswift","last_synced_at":"2025-06-21T05:06:26.916Z","repository":{"id":63910104,"uuid":"513451337","full_name":"Flowduino/ThreadSafeSwift","owner":"Flowduino","description":"Library of Types and Property Wrappers designed to provide Thread Safety simply and quickly for any Swift project","archived":false,"fork":false,"pushed_at":"2022-09-03T20:05:08.000Z","size":14,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-15T20:02:40.774Z","etag":null,"topics":["swift","thread","threading","threads","threadsafe"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Flowduino.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["Flowduino"]}},"created_at":"2022-07-13T09:02:53.000Z","updated_at":"2024-12-05T10:47:41.000Z","dependencies_parsed_at":"2022-11-29T07:11:27.141Z","dependency_job_id":null,"html_url":"https://github.com/Flowduino/ThreadSafeSwift","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Flowduino/ThreadSafeSwift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flowduino%2FThreadSafeSwift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flowduino%2FThreadSafeSwift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flowduino%2FThreadSafeSwift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flowduino%2FThreadSafeSwift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Flowduino","download_url":"https://codeload.github.com/Flowduino/ThreadSafeSwift/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flowduino%2FThreadSafeSwift/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261066503,"owners_count":23104768,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["swift","thread","threading","threads","threadsafe"],"created_at":"2025-01-18T15:55:11.971Z","updated_at":"2025-06-21T05:06:21.898Z","avatar_url":"https://github.com/Flowduino.png","language":"Swift","funding_links":["https://github.com/sponsors/Flowduino"],"categories":[],"sub_categories":[],"readme":"# ThreadSafeSwift\n\n\u003cp\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Swift-5.1%2B-yellowgreen.svg?style=flat\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" /\u003e\n    \u003ca href=\"https://github.com/apple/swift-package-manager\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/spm-compatible-brightgreen.svg?style=flat\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nCollection of Property Wrappers and other Types explicitly designed to provide quick, simple, and efficient Thread-Safety in your Swift projects.\n\n## Installation\n### Xcode Projects\nSelect `File` -\u003e `Swift Packages` -\u003e `Add Package Dependency` and enter `https://github.com/Flowduino/ThreadSafeSwift.git`\n\n### Swift Package Manager Projects\nYou can use `ThreadSafeSwift` as a Package Dependency in your own Packages' `Package.swift` file:\n```swift\nlet package = Package(\n    //...\n    dependencies: [\n        .package(\n            url: \"https://github.com/Flowduino/ThreadSafeSwift.git\",\n            .upToNextMajor(from: \"1.1.0\")\n        ),\n    ],\n    //...\n)\n```\n\nFrom there, refer to `ThreadSafeSwift` as a \"target dependency\" in any of _your_ package's targets that need it.\n\n```swift\ntargets: [\n    .target(\n        name: \"YourLibrary\",\n        dependencies: [\n          \"ThreadSafeSwift\",\n        ],\n        //...\n    ),\n    //...\n]\n```\nYou can then do `import ThreadSafeSwift` in any code that requires it.\n\n## Usage\n\nHere are some quick and easy usage examples for the features provided by `ThreadSafeSwift`:\n\n### `@ThreadSafeSemaphore` - Property Wrapper\nYou can use the `ThreadSafeSemaphore` Property Wrapper to encapsulate any Value Type behind a Thread-Safe `DispatchSemaphore`.\nThis is extremely easy for most types:\n```swift\n@ThreadSafeSemaphore var myInt: Int\n```\n\nFurther, you can access the underlying `DispatchSemaphore` directly, which is useful where you need to acquire the Lock for multiple operations that must performed *Atomically*:\n```swift\n@ThreadSafeSemaphore var myInts: [Int]\n\n//...\n\nfunc incrementEveryIntegerByOne() {\n    _myInts.lock.wait()\n    for (index,val) in myInts.enumerated() {\n        myInts[index] = val + 1\n    }\n    _myInts.lock.signal()\n}\n```\nOf course, for Arrays, you really should try to minimize the number of get/set operations required, and the duration throughout which the `DispatchSemaphore` is locked:\n```swift\n@ThreadSafeSemaphore var myInts: [Int]\n\n//...\n\nfunc incrementEveryIntegerByOne() {\n    var values = myInts // This would marshal the `DispatchSemaphore` and return a copy of the Array, then release the `DispatchSemaphore`\n    for (index,val) in values.enumerated() {\n        myInts[index] = val + 1\n    }\n    myInts = values // This would marshal the `DispatchSempahore` and replace the entire Array with our modified one, then release the `DispatchSemaphore`\n}\n```\n\n### `ThreadSafeSemaphore.withLock` - Execute a Closure while retaining the Lock\nOften, it is necessary to perform more than one operation on a Value... and when you need to do this, you'll want to ensure that you retain the `DispatchSemaphore` lock against the value for the duration of these operations.\nTo facilitate this, we can use the `withLock` method against any `ThreadSafeSemaphore` decorated variable:\n```swift\n@ThreadSafeSemaphore var myInts: [Int] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] \n```\nHere we have a `ThreadSafeSemaphore` decorated Array of Integers.\n\nIf we want to perform any number of operations against any number of values within this Array, we can now do so in a thread-safe manner using `withLock`:\n```swift\nfunc incrementEachValueByOne() {\n    _myInts.withLock { value in\n        for (index, val) in value.enumerated() {\n            value[index] = val + 1\n        }\n    }\n}\n```\nPlease pay attention to the preceeding underscore `_` before `myInts` when invoking the `withLock` method. This is important, as the underscore instructs Swift to reference the Property Decorator rather than its `wrappedValue`.\n\n**IMPORTANT NOTE:** - You must *not* reference the variable itself (in the above example, `myInts`) within the scope of the Closure. If you do, the Thread will lock at that command and proceed no further. All mutations to the value must be performed against `value` as defined within the scope of the Closure itself (as shown above).\n\nSo, as you can see, we can now encapsulate *complex types* with the `@ThreadSafeSemaphore` decorator and operate against all of its members within the safety of the `DispatchSemaphore` lock.\n\n### `ThreadSafeSemaphore.withTryLock` - Execute a Closure while retaining the Lock IF we can acquire it, otherwise execute a failure Closure\nAs with `ThreadSafeSemaphore.withLock` (explained above), we may need to perform one or more operations within the context of the `DispatchSemaphore` only *if* it is possible to obtain the `DispatchSemaphore` Lock at that time. Where it is not possible to acquire the `DispatchSemaphore` lock at that moment, we may want to execute another piece of conditional code.\n\nWe can do that easily:\n```swift\n@ThreadSafeSemaphore var myInts: [Int] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n```\nAgain, we declare our `@ThreadSafeSemaphore` decorated Variable.\n\nNow let's see how we would use `withTryLock` against `myInts`:\n```swift\nfunc incrementEachValueByOne() {\n    _myInts.withTryLock { value in\n        // If we got the Lock\n        for (index, val) in value.enumerated() {\n            value[index] = val + 1\n        }\n    } _: {\n        // If we couldn't get the Lock\n        print(\"We wanted to acquire the Lock, but couldn't... so we can do something else instead!\")\n    }\n}\n```\n**IMPORTANT NOTE:** - You must *not* reference the variable itself (in the above example, `myInts`) within the scope of the *either* Closure. If you do, the Thread will lock at that command and proceed no further. All mutations to the value must be performed against `value` as defined within the scope of the Closure itself (as shown above).\n\nThese *Conditional Closures* are extremely useful where your code needs to progress down a different execution path depending on whether it can or cannot acquire the `DispatchSemaphore` lock at the point of execution.\n\n**TIP:** - I use this very approach to implement \"Revolving Door Locks\" for Collections. A feature that will be added to this library very soon!\n\n## License\n\n`ThreadSafeSwift` is available under the MIT license. See the [LICENSE file](./LICENSE) for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflowduino%2Fthreadsafeswift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflowduino%2Fthreadsafeswift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflowduino%2Fthreadsafeswift/lists"}