{"id":26275698,"url":"https://github.com/hainayanda/chary","last_synced_at":"2025-05-06T16:05:03.048Z","repository":{"id":41265427,"uuid":"498583637","full_name":"hainayanda/Chary","owner":"hainayanda","description":"Thread Utility library","archived":false,"fork":false,"pushed_at":"2024-01-12T13:56:15.000Z","size":283,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-16T01:48:39.583Z","etag":null,"topics":["asynchronous","asynchronous-programming","atomic","dispatchque","multithreading","race-conditions","synchronous","thread","threading"],"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/hainayanda.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-06-01T03:57:22.000Z","updated_at":"2024-02-29T11:53:41.000Z","dependencies_parsed_at":"2022-08-25T20:41:04.036Z","dependency_job_id":"d22bbfb2-28cd-44cb-945f-577497230f51","html_url":"https://github.com/hainayanda/Chary","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hainayanda%2FChary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hainayanda%2FChary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hainayanda%2FChary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hainayanda%2FChary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hainayanda","download_url":"https://codeload.github.com/hainayanda/Chary/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252720310,"owners_count":21793737,"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":["asynchronous","asynchronous-programming","atomic","dispatchque","multithreading","race-conditions","synchronous","thread","threading"],"created_at":"2025-03-14T10:17:38.108Z","updated_at":"2025-05-06T16:05:03.024Z","avatar_url":"https://github.com/hainayanda.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Chary\n\nChary is a DispatchQueue Utilities for safer sync and asynchronous programming. It helps to avoid a race condition when dealing with multithreaded application\n\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/acc82b746a3345b6a7e91b249c52b50f)](https://www.codacy.com/gh/hainayanda/Chary/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=hainayanda/Chary\u0026amp;utm_campaign=Badge_Grade)\n![build](https://github.com/hainayanda/Chary/workflows/build/badge.svg)\n![test](https://github.com/hainayanda/Chary/workflows/test/badge.svg)\n[![SwiftPM Compatible](https://img.shields.io/badge/SwiftPM-Compatible-brightgreen)](https://swift.org/package-manager/)\n[![Version](https://img.shields.io/cocoapods/v/Chary.svg?style=flat)](https://cocoapods.org/pods/Chary)\n[![License](https://img.shields.io/cocoapods/l/Chary.svg?style=flat)](https://cocoapods.org/pods/Chary)\n[![Platform](https://img.shields.io/cocoapods/p/Chary.svg?style=flat)](https://cocoapods.org/pods/Chary)\n\n\n## Requirements\n\n- Swift 5.0 or higher (or 5.3 when using Swift Package Manager)\n- iOS 10.0 or higher\n- macOS 10.0 or higher\n- tvOS 10.10 or higher\n- watchOS 4 or higher\n\n## Installation\n\n### Cocoapods\n\nChary is available through [CocoaPods](https://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\npod 'Chary'\n```\n\n### Swift Package Manager from XCode\n\n- Add it using XCode menu **File \u003e Swift Package \u003e Add Package Dependency**\n- Add **\u003chttps://github.com/hainayanda/Chary.git\u003e** as Swift Package URL\n- Set rules at **version**, with **Up to Next Major** option and put **1.0.7** as its version\n- Click next and wait\n\n### Swift Package Manager from Package.swift\n\nAdd as your target dependency in **Package.swift**\n\n```swift\ndependencies: [\n  .package(url: \"https://github.com/hainayanda/Chary.git\", .upToNextMajor(from: \"1.0.7\"))\n]\n```\n\nUse it in your target as `Chary`\n\n```swift\n .target(\n    name: \"MyModule\",\n    dependencies: [\"Chary\"]\n)\n```\n\n## Author\n\nNayanda Haberty, hainayanda@outlook.com\n\n## License\n\nPharos is available under the MIT license. See the LICENSE file for more info.\n\n***\n\n## Basic Usage\n\nTwo utilities come with Chary, `Atomic` propertyWrapper and `DispatchQueue` extensions\n\n## Atomic propertyWrapper\n\nAtomic propertyWrapper is a propertyWrapper to wrap a property so it could be accessed and edited atomically:\n\n```swift\nclass MyClass {\n    @Atomic var atomicString: String = \"atomicString\"\n    ...\n    ...\n}\n```\n\nthen the atomicString will be Thread safe regardless of where it is accessed or edited.\n\n```swift\nDispatchQueue.main.async {\n    myClass.atomicString = \"from main thread\"\n}\nDispatchQueue.global().async {\n    myClass.atomicString = \"from global thread\"\n}\n```\n\n## DispatchQueue Extensions\n\nChary has some DispatchQueue Extension that will help when dealing with multithreaded.\n\n### Check current queue\n\nYou can check current DispatchQueue using `isCurrentQueue(is:)` which will check is the queue given is the current queue or not.\n\n```swift\nmyQueue = DispatchQueue(label: \"myQueue\")\nmyQueue.sync {\n    // this will print true\n    print(DispatchQueue.isCurrentQueue(is: myQueue))\n}\n// this will print false\nprint(DispatchQueue.isCurrentQueue(is: myQueue))\n```\n\nWhat it did do is registering the DispatchQueue given for detection and compare the current detectable queues with the given one:\n\n```swift\npublic static func isCurrentQueue(is queue: DispatchQueue) -\u003e Bool {\n    queue.registerDetection()\n    return current == queue\n}\n```\n\nCalling `DispatchQueue.current` will not guarantee to return the current `DispatchQueue`, since it can only return only `DispatchQueue` that already been registered for detection.\nThere are some default `DispatchQueue` that will auto registered when `current` is called:\n- `DispatchQueue.main`\n- `DispatchQueue.global()`\n- `DispatchQueue.global(qos: .background)`\n- `DispatchQueue.global(qos: .default)`\n- `DispatchQueue.global(qos: .unspecified)`\n- `DispatchQueue.global(qos: .userInitiated)`\n- `DispatchQueue.global(qos: .userInteractive)`\n- `DispatchQueue.global(qos: .utility)`\n\nOther than that, it will need manual call for `registerDetection()` to allow the `DispatchQueue` to be accesible by calling `DispatchQueue.current`. Since `isCurrentQueue(is:)` will automatically register the given `DispatchQueue`, the queue passed will be accesible from `DispatchQueue.current` after.\n\n### Safe Sync\n\nRunning `sync` from `DispatchQueue` sometimes can raise an exception if it is called in the same `DispatchQueue`. \nTo avoid this, you can use `safeSync` instead which will check the current queue first and decide whether it needs to run the block right away or by using the default `sync`.\nYou don't need to register the `DispatchQueue` since it will automatically register the `DispatchQueue` before checking:\n\n```swift\nDispatchQueue.main.safeSync {\n    print(\"this will safely executed\")\n}\n```\n\n### Async if needed\n\nSometimes you want to execute the operation right away if it's in the right `DispatchQueue` instead of running it asynchronously by using `async`.\nLike when you update UI, it's better if you run it right away instead of putting it in the asynchronous queue if you are already in DispatchQueue.main.\nYou can use `asyncIfNeeded` to achieve that functionality right away. It will check the current `DispatchQueue` and decide whether it needs to run right away or by using the default `async`.\nYou don't need to register the `DispatchQueue` since it will automatically register the `DispatchQueue` before checking:\n\n```swift\nDispatchQueue.main.asyncIfNeeded {\n    print(\"this will executed right away or asynchronously if in different queue\")\n}\n```\n\n***\n\n## Contribute\n\nYou know-how. Just clone and do a pull request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhainayanda%2Fchary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhainayanda%2Fchary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhainayanda%2Fchary/lists"}