[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-6869":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":15,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":17,"rankGlobal":9,"rankLanguage":9,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":9,"pushedAt":9,"updatedAt":23,"readmeContent":24,"aiSummary":25,"trendingCount":15,"starSnapshotCount":15,"syncStatus":16,"lastSyncTime":26,"discoverSource":27},6869,"Async","duemunk\u002FAsync","duemunk","Syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch",null,"Swift",4565,311,70,3,0,2,59.68,"MIT License",false,"master",true,[],"2026-06-12 04:00:30","This project is no longer maintained.\n\n# Async\n[![](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002FOS%20X-10.10%2B-blue.svg)]() [![](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002FiOS-8.0%2B-blue.svg)]() [![](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002FtvOS-9.0%2B-blue.svg)]() [![](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002FwatchOS-2.0%2B-blue.svg)]() [![](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002FSwift-5.1-blue.svg)]() [![](https:\u002F\u002Ftravis-ci.org\u002Fduemunk\u002FAsync.svg)](https:\u002F\u002Ftravis-ci.org\u002Fduemunk\u002FAsync) [![Carthage compatible](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FCarthage-compatible-4BC51D.svg)](https:\u002F\u002Fgithub.com\u002FCarthage\u002FCarthage) [![CocoaPods compatible](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FCocoaPods-compatible-4BC51D.svg)](https:\u002F\u002Fgithub.com\u002FCocoaPods\u002FCocoaPods) [![](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002Foperator_overload-nope-green.svg)](https:\u002F\u002Fgist.github.com\u002Fduemunk\u002F61e45932dbb1a2ca0954)\n\n\n\nNow more than syntactic sugar for asynchronous dispatches in Grand Central Dispatch ([GCD](https:\u002F\u002Fdeveloper.apple.com\u002Flibrary\u002Fprerelease\u002Fios\u002Fdocumentation\u002FPerformance\u002FReference\u002FGCD_libdispatch_Ref\u002Findex.html)) in Swift\n\n**Async** sugar looks like this:\n```swift\nAsync.userInitiated {\n\t10\n}.background {\n\t\"Score: \\($0)\"\n}.main {\n\tlabel.text = $0\n}\n```\n\nSo even though GCD has nice-ish syntax as of Swift 3.0, compare the above with:\n```swift\nDispatchQueue.global(qos: .userInitiated).async {\n\tlet value = 10\n\tDispatchQueue.global(qos: .background).async {\n\t\tlet text = \"Score: \\(value)\"\n\t\tDispatchQueue.main.async {\n\t\t\tlabel.text = text\n\t\t}\n\t}\n}\n```\n\n**AsyncGroup** sugar looks like this:\n```swift\nlet group = AsyncGroup()\ngroup.background {\n    print(\"This is run on the background queue\")\n}\ngroup.background {\n    print(\"This is also run on the background queue in parallel\")\n}\ngroup.wait()\nprint(\"Both asynchronous blocks are complete\")\n```\n\n### Install\n#### Swift Package Manager\n##### Add To Your Project In Xcode 11:\nFile > Swift Packages > Add Package Dependency\n##### Add As A Dependency In Package.swift:\n```swift\ndependencies: [\n    .package(url: \"https:\u002F\u002Fgithub.com\u002Fduemunk\u002FAsync\", from: \"2.1.0\"),\n],\n```\n#### CocoaPods\n```ruby\nuse_frameworks!\npod \"AsyncSwift\"\n```\n#### Carthage\n```ruby\ngithub \"duemunk\u002FAsync\"\n```\n\n### Benefits\n1. Avoid code indentation by chaining\n2. Arguments and return types reduce polluted scopes\n\n### Things you can do\nSupports the modern queue classes:\n```swift\nAsync.main {}\nAsync.userInteractive {}\nAsync.userInitiated {}\nAsync.utility {}\nAsync.background {}\n```\n\nChain as many blocks as you want:\n```swift\nAsync.userInitiated {\n\t\u002F\u002F 1\n}.main {\n\t\u002F\u002F 2\n}.background {\n\t\u002F\u002F 3\n}.main {\n\t\u002F\u002F 4\n}\n```\n\nStore reference for later chaining:\n```swift\nlet backgroundBlock = Async.background {\n\tprint(\"This is run on the background queue\")\n}\n\n\u002F\u002F Run other code here...\n\n\u002F\u002F Chain to reference\nbackgroundBlock.main {\n\tprint(\"This is run on the \\(qos_class_self().description) (expected \\(qos_class_main().description)), after the previous block\")\n}\n```\n\nCustom queues:\n```swift\nlet customQueue = DispatchQueue(label: \"CustomQueueLabel\", attributes: [.concurrent])\nlet otherCustomQueue = DispatchQueue(label: \"OtherCustomQueueLabel\")\nAsync.custom(queue: customQueue) {\n\tprint(\"Custom queue\")\n}.custom(queue: otherCustomQueue) {\n\tprint(\"Other custom queue\")\n}\n```\n\nDispatch block after delay:\n```swift\nlet seconds = 0.5\nAsync.main(after: seconds) {\n\tprint(\"Is called after 0.5 seconds\")\n}.background(after: 0.4) {\n\tprint(\"At least 0.4 seconds after previous block, and 0.9 after Async code is called\")\n}\n```\n\nCancel blocks that aren't already dispatched:\n```swift\n\u002F\u002F Cancel blocks not yet dispatched\nlet block1 = Async.background {\n\t\u002F\u002F Heavy work\n\tfor i in 0...1000 {\n\t\tprint(\"A \\(i)\")\n\t}\n}\nlet block2 = block1.background {\n\tprint(\"B – shouldn't be reached, since cancelled\")\n}\nAsync.main {\n\t\u002F\u002F Cancel async to allow block1 to begin\n\tblock1.cancel() \u002F\u002F First block is _not_ cancelled\n\tblock2.cancel() \u002F\u002F Second block _is_ cancelled\n}\n```\n\nWait for block to finish – an ease way to continue on current queue after background task:\n```swift\nlet block = Async.background {\n\t\u002F\u002F Do stuff\n}\n\n\u002F\u002F Do other stuff\n\nblock.wait()\n```\n\n### How does it work\nThe way it work is by using the new notification API for GCD introduced in OS X 10.10 and iOS 8. Each chaining block is called when the previous queue has finished.\n```swift\nlet previousBlock = {}\nlet chainingBlock = {}\nlet dispatchQueueForChainingBlock = ...\n\n\u002F\u002F Use the GCD API to extend the blocks\nlet _previousBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, previousBlock)\nlet _chainingBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, chainingBlock)\n\n\u002F\u002F Use the GCD API to call back when finishing the \"previous\" block\ndispatch_block_notify(_previousBlock, dispatchQueueForChainingBlock, _chainingBlock)\n```\n\nThe syntax part of the chaining works by having class methods on the `Async` object e.g. `Async.main {}` which returns a struct. The struct has matching methods e.g. `theStruct.main {}`.\n\n### Known bugs\nModern GCD queues don't work as expected in the iOS Simulator. See issues [13](https:\u002F\u002Fgithub.com\u002Fduemunk\u002FAsync\u002Fissues\u002F13), [22](https:\u002F\u002Fgithub.com\u002Fduemunk\u002FAsync\u002Fissues\u002F22).\n\n### Known improvements\nThe ```dispatch_block_t``` can't be extended. Workaround used: Wrap ```dispatch_block_t``` in a struct that takes the block as a property.\n\n### Apply\nThere is also a wrapper for [`dispatch_apply()`](https:\u002F\u002Fdeveloper.apple.com\u002Flibrary\u002Fmac\u002Fdocumentation\u002FPerformance\u002FReference\u002FGCD_libdispatch_Ref\u002Findex.html#\u002F\u002Fapple_ref\u002Fc\u002Ffunc\u002Fdispatch_apply)  for quick parallelisation of a `for` loop.\n```swift\nApply.background(100) { i in\n\t\u002F\u002F Do stuff e.g. print(i)\n}\n```\nNote that this function returns after the block has been run all 100 times i.e. it is not asynchronous. For asynchronous behaviour, wrap it in a an `Async` block like `Async.background { Apply.background(100) { ... } }`.\n\n### AsyncGroup\n**AsyncGroup** facilitates working with groups of asynchronous blocks.\n\nMultiple dispatch blocks with GCD:\n```swift\nlet group = AsyncGroup()\ngroup.background {\n    \u002F\u002F Run on background queue\n}\ngroup.utility {\n    \u002F\u002F Run on utility queue, in parallel to the previous block\n}\ngroup.wait()\n```\nAll modern queue classes:\n```swift\ngroup.main {}\ngroup.userInteractive {}\ngroup.userInitiated {}\ngroup.utility {}\ngroup.background {}\n```\nCustom queues:\n```swift\nlet customQueue = dispatch_queue_create(\"Label\", DISPATCH_QUEUE_CONCURRENT)\ngroup.custom(queue: customQueue) {}\n```\nWait for group to finish:\n```swift\nlet group = AsyncGroup()\ngroup.background {\n    \u002F\u002F Do stuff\n}\ngroup.background {\n    \u002F\u002F Do other stuff in parallel\n}\n\u002F\u002F Wait for both to finish\ngroup.wait()\n\u002F\u002F Do rest of stuff\n```\nCustom asynchronous operations:\n```swift\nlet group = AsyncGroup()\ngroup.enter()\ndispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {\n    \u002F\u002F Do stuff\n    group.leave()\n}\ngroup.enter()\ndispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {\n    \u002F\u002F Do other stuff in parallel\n    group.leave()\n}\n\u002F\u002F Wait for both to finish\ngroup.wait()\n\u002F\u002F Do rest of stuff\n```\n\n### License\nThe MIT License (MIT)\n\nCopyright (c) 2016 Tobias Due Munk\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and\u002For sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","Async 是一个用于在 Swift 中简化 Grand Central Dispatch (GCD) 异步调度的语法糖库。其核心功能包括通过链式调用减少代码缩进，支持多种队列类型（如主队列、用户交互队列等），并且能够传递参数和返回值以保持作用域清晰。此外，Async 还提供了 AsyncGroup 来管理并行执行的任务组，并确保所有任务完成后再继续执行后续操作。尽管该项目已不再维护，但它仍然适用于需要提高 GCD 代码可读性和简洁性的 iOS、macOS、tvOS 和 watchOS 应用开发场景中。","2026-06-11 03:09:19","top_language"]