- 
                Notifications
    
You must be signed in to change notification settings  - Fork 0
 
feat: Initial implementation of many GCD API's using Swift Concurrency #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
          
     Merged
      
      
    
  
     Merged
                    Changes from 58 commits
      Commits
    
    
            Show all changes
          
          
            59 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      1a8946b
              
                chore: refine gitignore
              
              
                scottmarchant 940349b
              
                chore: Set up initial swift package manifest file.
              
              
                scottmarchant d90e8b8
              
                feat: Implement DispatchQueue using Swift Concurrency.
              
              
                scottmarchant 2ecbb15
              
                feat: Implement DispatchGroup using Swift Concurrency.
              
              
                scottmarchant 5108dec
              
                feat: Implement DispatchSemaphore using Swift Concurrency.
              
              
                scottmarchant d98950c
              
                feat: Implement DispatchTime using Swift Concurrency.
              
              
                scottmarchant 64036b9
              
                feat: Implement DispatchTimeInterval using Swift Concurrency.
              
              
                scottmarchant 40b798d
              
                chore: Add some basic testing.
              
              
                scottmarchant da07ce2
              
                chore: Update Readme.
              
              
                scottmarchant aed4dd6
              
                ci: Add pull request CI workflows.
              
              
                scottmarchant f8d723e
              
                chore: Silence some lint that is intentionally written this way to ma…
              
              
                scottmarchant dae1d1d
              
                ci: Disable api breakage check for now.
              
              
                scottmarchant e2e3b83
              
                ci: Don't test swift versions before 6.1
              
              
                scottmarchant b5abf14
              
                chore: Update file headers
              
              
                scottmarchant ec5c7da
              
                chore: Changing wording in readme.
              
              
                scottmarchant c87843c
              
                chore: Ignore missing license header in Package.swift file.
              
              
                scottmarchant 1a3e651
              
                chore: Clean up lint a different way.
              
              
                scottmarchant 91599e9
              
                ci: update test targets
              
              
                scottmarchant f78c0d5
              
                ci: Add wasm sdk installation script.
              
              
                scottmarchant e3af2d2
              
                chore: Fix license header format in bash script.
              
              
                scottmarchant 1e8b322
              
                chore: Update swift-format rules.
              
              
                scottmarchant f64e771
              
                chore: Add convenience scripts to run the same commands CI uses for s…
              
              
                scottmarchant f38c234
              
                chore: Fix license setup for soundness checks.
              
              
                scottmarchant 716c184
              
                chore: Removing lint rule definitions not recognized by github online…
              
              
                scottmarchant b698b1b
              
                ci: Don't run tests on Swift 5.10 either. Not supported.
              
              
                scottmarchant fac6c98
              
                fix: Fix potential main thread issue in DispatchQueue that currently …
              
              
                scottmarchant 2c92ea9
              
                ci: Try a slightly different mechanism to get the swift version, to a…
              
              
                scottmarchant 67011b5
              
                chore: update scripting
              
              
                scottmarchant 1f4c5c8
              
                chore: Fix lint that CI wants one way, and local install wants a diff…
              
              
                scottmarchant aa4565b
              
                ci: Use my own bash adapted from Yuta Saito's open MR to build wasm f…
              
              
                scottmarchant cada3e8
              
                ci: move scripts inline to yml configuration to work around issues wi…
              
              
                scottmarchant 69e8aee
              
                test: Update unit tests to adjust expectations for linux targets. Lin…
              
              
                scottmarchant e2ee220
              
                ci: Install jq for wasm builds.
              
              
                scottmarchant 9ad3a89
              
                fix: Fix unit test expectations for linux. Take two.
              
              
                scottmarchant 4ac2494
              
                chore: lint
              
              
                scottmarchant e271490
              
                ci: wasm build needs to clone the code before it can build.
              
              
                scottmarchant 0950a4f
              
                ci: use Swift 6.1 for wasm build.
              
              
                scottmarchant a29c5aa
              
                ci: Specifical swift 6.1.0 for wasm builds, not swift 6.1.2.
              
              
                scottmarchant 33536b0
              
                chore: Fix incomplete comment.
              
              
                scottmarchant 9df1a12
              
                fix: Fix a variety of issues found in DispatchAsync while implementin…
              
              
                scottmarchant 2fb14f7
              
                chore: Use swift version 6.0 as the minimum rather than 6.1.
              
              
                scottmarchant 5ba8280
              
                refactor: Update ifdefs and @_spi guards to allow development against…
              
              
                scottmarchant 671380d
              
                refactor: Change copyright owner to PassiveLogic for now.
              
              
                scottmarchant 375a973
              
                chore: Run swift-format
              
              
                scottmarchant 205d5a4
              
                chore: Add permalink to copy-pasted file.
              
              
                scottmarchant e507fa4
              
                docs: Add usage notes with plenty of warnings.
              
              
                scottmarchant c008610
              
                docs: Add info about license.
              
              
                scottmarchant 29589c5
              
                ci: Disable license header check in CI for now.
              
              
                scottmarchant cc6c387
              
                chore: See if this address weird lint issue popping up in CI.
              
              
                scottmarchant cfe3db3
              
                chore: Address lint error for Package.swift:19:15: error: expected va…
              
              
                scottmarchant bc50dff
              
                ci: Use a later version of swift for the swift-format check. This sho…
              
              
                scottmarchant e878eb9
              
                ci: Updating swift-format rule for swift 6.1.0 instead of swift 6.2.
              
              
                scottmarchant 0cfc4e3
              
                chore: Update a few more file headers.
              
              
                scottmarchant 8267093
              
                chore: Update swift to Swift in comments
              
              
                scottmarchant 1a332dc
              
                chore: update more swift vs Swift language
              
              
                scottmarchant 7540247
              
                chore: Parameterize number of iterations for critical unit test.
              
              
                scottmarchant 3c3df38
              
                chore: Fix typo.
              
              
                scottmarchant b5d25d5
              
                refactor: rename package to follow existing patterns in Apple's Swift…
              
              
                scottmarchant cb50499
              
                chore: refine documentation.
              
              
                scottmarchant File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| name: Pull request | ||
| 
     | 
||
| on: | ||
| pull_request: | ||
| types: [opened, reopened, synchronize] | ||
| 
     | 
||
| jobs: | ||
| soundness: | ||
| name: Soundness | ||
| uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main | ||
| with: | ||
| format_check_container_image: swift:6.1.0-noble | ||
| license_header_check_enabled: false | ||
| api_breakage_check_enabled: false | ||
| 
     | 
||
| tests: | ||
| name: tests | ||
| uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main | ||
| with: | ||
| enable_macos_checks: false | ||
| linux_exclude_swift_versions: "[{\"swift_version\": \"5.9\"}, {\"swift_version\": \"5.10\"}, {\"swift_version\": \"5.10.1\"}, {\"swift_version\": \"6.0\"}]" | ||
| enable_windows_checks: false | ||
| 
     | 
||
| wasm-sdk: | ||
| name: WebAssembly SDK | ||
| runs-on: ubuntu-latest | ||
| container: | ||
| image: "swift:6.1.0-noble" | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| - name: Swift version | ||
| run: swift --version | ||
| - name: WasmBuild | ||
| # TODO: Update this to use swift-nio once https://github.com/apple/swift-nio/pull/3159/ is merged | ||
| run: | | ||
| apt-get update -y -q | ||
| apt-get install -y -q curl | ||
| apt-get install -y -q jq | ||
| version="$(swift --version | head -n1)" | ||
| tag="$(curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/tag-by-version.json" | jq -e -r --arg v "$version" '.[$v] | .[-1]')" | ||
| curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/builds/$tag.json" | jq -r '.["swift-sdks"]["wasm32-unknown-wasi"] | "swift sdk install \"\(.url)\" --checksum \"\(.checksum)\""' | sh -x | ||
| swift build --swift-sdk wasm32-unknown-wasi | ||
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,62 +1,8 @@ | ||
| # Xcode | ||
| # | ||
| # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore | ||
| 
     | 
||
| ## User settings | ||
| .DS_Store | ||
| /.build | ||
| /Packages | ||
| xcuserdata/ | ||
| 
     | 
||
| ## Obj-C/Swift specific | ||
| *.hmap | ||
| 
     | 
||
| ## App packaging | ||
| *.ipa | ||
| *.dSYM.zip | ||
| *.dSYM | ||
| 
     | 
||
| ## Playgrounds | ||
| timeline.xctimeline | ||
| playground.xcworkspace | ||
| 
     | 
||
| # Swift Package Manager | ||
| # | ||
| # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. | ||
| # Packages/ | ||
| # Package.pins | ||
| # Package.resolved | ||
| # *.xcodeproj | ||
| # | ||
| # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata | ||
| # hence it is not needed unless you have added a package configuration file to your project | ||
| # .swiftpm | ||
| 
     | 
||
| .build/ | ||
| 
     | 
||
| # CocoaPods | ||
| # | ||
| # We recommend against adding the Pods directory to your .gitignore. However | ||
| # you should judge for yourself, the pros and cons are mentioned at: | ||
| # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control | ||
| # | ||
| # Pods/ | ||
| # | ||
| # Add this line if you want to avoid checking in source code from the Xcode workspace | ||
| # *.xcworkspace | ||
| 
     | 
||
| # Carthage | ||
| # | ||
| # Add this line if you want to avoid checking in source code from Carthage dependencies. | ||
| # Carthage/Checkouts | ||
| 
     | 
||
| Carthage/Build/ | ||
| 
     | 
||
| # fastlane | ||
| # | ||
| # It is recommended to not store the screenshots in the git repo. | ||
| # Instead, use fastlane to re-generate the screenshots whenever they are needed. | ||
| # For more information about the recommended setup visit: | ||
| # https://docs.fastlane.tools/best-practices/source-control/#source-control | ||
| 
     | 
||
| fastlane/report.xml | ||
| fastlane/Preview.html | ||
| fastlane/screenshots/**/*.png | ||
| fastlane/test_output | ||
| DerivedData/ | ||
| .swiftpm/configuration/registries.json | ||
| .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata | ||
| .netrc | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Package.swift | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| { | ||
| "fileScopedDeclarationPrivacy" : { | ||
| "accessLevel" : "private" | ||
| }, | ||
| "indentConditionalCompilationBlocks" : false, | ||
| "indentSwitchCaseLabels" : false, | ||
| "indentation" : { | ||
| "spaces" : 4 | ||
| }, | ||
| "lineBreakAroundMultilineExpressionChainComponents" : false, | ||
| "lineBreakBeforeControlFlowKeywords" : false, | ||
| "lineBreakBeforeEachArgument" : false, | ||
| "lineBreakBeforeEachGenericRequirement" : false, | ||
| "lineBreakBetweenDeclarationAttributes" : false, | ||
| "lineLength" : 140, | ||
| "maximumBlankLines" : 1, | ||
| "multiElementCollectionTrailingCommas" : true, | ||
| "noAssignmentInExpressions" : { | ||
| "allowedFunctions" : [ | ||
| "XCTAssertNoThrow" | ||
| ] | ||
| }, | ||
| "prioritizeKeepingFunctionOutputTogether" : false, | ||
| "reflowMultilineStringLiterals" : { | ||
| "never" : { | ||
| 
     | 
||
| } | ||
| }, | ||
| "respectsExistingLineBreaks" : true, | ||
| "rules" : { | ||
| "AllPublicDeclarationsHaveDocumentation" : false, | ||
| "AlwaysUseLiteralForEmptyCollectionInit" : false, | ||
| "AlwaysUseLowerCamelCase" : true, | ||
| "AmbiguousTrailingClosureOverload" : true, | ||
| "AvoidRetroactiveConformances" : true, | ||
| "BeginDocumentationCommentWithOneLineSummary" : false, | ||
| "DoNotUseSemicolons" : true, | ||
| "DontRepeatTypeInStaticProperties" : true, | ||
| "FileScopedDeclarationPrivacy" : true, | ||
| "FullyIndirectEnum" : true, | ||
| "GroupNumericLiterals" : true, | ||
| "IdentifiersMustBeASCII" : true, | ||
| "NeverForceUnwrap" : false, | ||
| "NeverUseForceTry" : false, | ||
| "NeverUseImplicitlyUnwrappedOptionals" : false, | ||
| "NoAccessLevelOnExtensionDeclaration" : true, | ||
| "NoAssignmentInExpressions" : true, | ||
| "NoBlockComments" : true, | ||
| "NoCasesWithOnlyFallthrough" : true, | ||
| "NoEmptyLinesOpeningClosingBraces" : false, | ||
| "NoEmptyTrailingClosureParentheses" : true, | ||
| "NoLabelsInCasePatterns" : true, | ||
| "NoLeadingUnderscores" : false, | ||
| "NoParensAroundConditions" : true, | ||
| "NoPlaygroundLiterals" : true, | ||
| "NoVoidReturnOnFunctionSignature" : true, | ||
| "OmitExplicitReturns" : false, | ||
| "OneCasePerLine" : true, | ||
| "OneVariableDeclarationPerLine" : true, | ||
| "OnlyOneTrailingClosureArgument" : true, | ||
| "OrderedImports" : true, | ||
| "ReplaceForEachWithForLoop" : true, | ||
| "ReturnVoidInsteadOfEmptyTuple" : true, | ||
| "TypeNamesShouldBeCapitalized" : true, | ||
| "UseEarlyExits" : false, | ||
| "UseExplicitNilCheckInConditions" : true, | ||
| "UseLetInEveryBoundCaseVariable" : true, | ||
| "UseShorthandTypeNames" : true, | ||
| "UseSingleLinePropertyGetter" : true, | ||
| "UseSynthesizedInitializer" : true, | ||
| "UseTripleSlashForDocumentationComments" : true, | ||
| "UseWhereClausesInForLoops" : false, | ||
| "ValidateDocumentationComments" : false | ||
| }, | ||
| "spacesAroundRangeFormationOperators" : true, | ||
| "spacesBeforeEndOfLineComments" : 1, | ||
| "tabWidth" : 8, | ||
| "version" : 1 | ||
| } | 
            File renamed without changes.
          
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // swift-tools-version: 6.0 | ||
| 
     | 
||
| import PackageDescription | ||
| 
     | 
||
| let package = Package( | ||
| name: "swift-dispatch-async", | ||
| products: [ | ||
| .library( | ||
| name: "DispatchAsync", | ||
| targets: ["DispatchAsync"] | ||
| ) | ||
| ], | ||
| targets: [ | ||
| .target(name: "DispatchAsync"), | ||
| .testTarget( | ||
| name: "DispatchAsyncTests", | ||
| dependencies: [ | ||
| "DispatchAsync" | ||
| ] | ||
| ), | ||
| ] | ||
| ) | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1 +1,141 @@ | ||
| # dispatch-async | ||
| # swift-dispatch-async | ||
| 
     | 
||
| ## ⚠️ WARNING - This is an 🧪experimental🧪 repository and should not be adopted at large. | ||
| 
     | 
||
| DispatchAsync is a temporary experimental repository aimed at implementing missing Dispatch support in the SwiftWasm toolchain. | ||
| Currently, [SwiftWasm doesn't include Dispatch](https://book.swiftwasm.org/getting-started/porting.html#swift-foundation-and-dispatch). | ||
| But, SwiftWasm does support Swift Concurrency. DispatchAsync implements a number of common Dispatch API's using Swift Concurrency | ||
| under the hood. | ||
| 
     | 
||
| Dispatch Async does not provide blocking API's such as `DispatchQueue.sync`, primarily due to the intentional lack of blocking | ||
| API's in Swift Concurrency. | ||
| 
     | 
||
| # Toolchain Adoption Plans | ||
| 
     | 
||
| DispatchAsync is not meant for consumption abroad directly as a new Swift Module. Rather, the intention is to provide eventual integration | ||
| as a drop-in replacement for Dispatch when compiling to Wasm. | ||
| 
     | 
||
| There are a few paths to adoption into the Swift toolchain | ||
| 
     | 
||
| - DispatchAsync can be emplaced inside the [libDispatch repository](https://github.com/swiftlang/swift-corelibs-libdispatch), and compiled | ||
| into the toolchain only for wasm targets. | ||
| - DispatchAsync can be consumed in place of libDispatch when building the Swift toolchain. | ||
| 
     | 
||
| Ideally, with either approach, this repository would transfer ownership to the swiftlang organization. | ||
| 
     | 
||
| In the interim, to move wasm support forward, portions of DispatchAsync may be inlined (copy-pasted) | ||
| into various libraries to enable wasm support. DispatchAsync is designed for this purpose, and has | ||
| special `#if` handling to ensure that existing temporary usages will be elided without breakage | ||
| the moment SwiftWasm adds support for `Dispatch` into the toolchain. | ||
| 
     | 
||
| # DispatchSemaphore Limitations | ||
| 
     | 
||
| The current implementation of `DispatchSemaphore` has some limitations. Blocking threads goes against the design goals of Swift Concurrency. | ||
| The `wait` function on `DispatchSemaphore` goes against this goal. Furthermore, most wasm targets run on a single thread from the web | ||
                
      
                  scottmarchant marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| browser, so any time the `wait` function ends up blocking the calling thread, it would almost certainly freeze the single-threaded wasm | ||
| executable. | ||
| 
     | 
||
| To navigate these issues, there are some limitations: | ||
| 
     | 
||
| - For wasm compilation targets, `DispatchSemaphore` assumes single-threaded execution, and lacks various safeguards that would otherwise | ||
| be needed for multi-threaded execution. This makes the implementation much easier. | ||
| - For wasm targets, calls to `signal` and `wait` must be balanced. An assertion triggers if `wait` is called more times than `signal`. | ||
| - DispatchSemaphore is deprecated for wasm targets, and AsyncSemaphore is encouraged as the replacement. | ||
| - For non-wasm targets, DispatchSemaphore is simply a typealias for `AsyncSemaphore`, and provides only a non-blocking async `wait` | ||
| function. This reduces potential issues that can arise from wait being a thread-blocking function. | ||
| 
     | 
||
| # Usage | ||
| 
     | 
||
| If you've scrolled this far, you probably saw the warning. But just to make sure… | ||
| 
     | 
||
| > ⚠️ WARNING - This is an 🧪experimental🧪 repository and should not be adopted at large. | ||
| 
     | 
||
| PassiveLogic is [actively working](https://github.com/PassiveLogic/swift-web-examples/issues/1) to mainstream this into the SwiftWasm | ||
| toolchain. But if you can't wait, here are some tips. | ||
| 
     | 
||
| ## 1. Only use this for WASI platforms, and only if Dispatch cannot be imported. | ||
| 
     | 
||
| Use `#if os(WASI) && !canImport(Dispatch)` to elide usages outside of WASI platforms: | ||
| 
     | 
||
| ```swift | ||
| #if os(WASI) && !canImport(Dispatch) | ||
| import DispatchAsync | ||
| #else | ||
| import Dispatch | ||
| #endif | ||
| 
     | 
||
| // Use Dispatch API's the same way you normal would. | ||
| ``` | ||
| 
     | 
||
| ## 2. If you really want to use DispatchAsync as a pure Swift Dispatch alternative for non-wasm targets | ||
| 
     | 
||
| Stop. Are you sure? If you do this, you'll need to be ' | ||
                
      
                  scottmarchant marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| 1. Add the dependency to your package: | ||
| 
     | 
||
| ```swift | ||
| let package = Package( | ||
| name: "MyPackage", | ||
| products: [ | ||
| // Products define the executables and libraries a package produces, making them visible to other packages. | ||
                
      
                  scottmarchant marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| .library( | ||
| name: "MyPackage", | ||
| targets: [ | ||
| "MyPackage" | ||
| ] | ||
| ), | ||
| ], | ||
| dependencies: [ | ||
| .package( | ||
| url: "https://github.com/PassiveLogic/swift-dispatch-async.git", | ||
| from: "0.0.1" | ||
| ), | ||
| ], | ||
| targets: [ | ||
| .target( | ||
| name: "MyPackage" | ||
| dependencies: [ | ||
| "DispatchAsync" | ||
| ] | ||
| ), | ||
| ] | ||
| ) | ||
| ``` | ||
| 
     | 
||
| 2. Import and use DispatchAsync in place of Dispatch like this: | ||
| 
     | 
||
| ```swift | ||
| #if os(WASI) && !canImport(Dispatch) | ||
| import DispatchAsync | ||
| #else | ||
| // Non-WASI platforms have to explicitly bring in DispatchAsync | ||
| // by using `@_spi`. | ||
| @_spi(DispatchAsync) import DispatchAsync | ||
| #endif | ||
| 
     | 
||
| // Not allowed, brings in Dispatch, aka "the real GCD": | ||
| // import Dispatch | ||
| 
     | 
||
| // Also not allowed, brings in Dispatch | ||
| // import Foundation | ||
| 
     | 
||
| // You'll need to use scoped Foundation imports: | ||
| import struct Foundation.URL // Ok. Doesn't bring in Dispatch | ||
| 
     | 
||
| // If you ignore the above notes, but do the following, be prepared for namespace | ||
| // collisions between the toolchain's Dispatch and DispatchAsync: | ||
| 
     | 
||
| private typealias DispatchQueue = DispatchAsync.DispatchQueue // Ok as long as Dispatch isn't imported | ||
| 
     | 
||
| // Ok. If you followed everything above, you can now do the following, using pure Swift | ||
| // under the hood! 🎉 | ||
| DispatchQueue.main.async { | ||
| // Run your code here… | ||
| } | ||
| ``` | ||
| 
     | 
||
| # LICENSE | ||
| 
     | 
||
| This project is distributed by PassiveLogic under the Apache-2.0 license. See | ||
| [LICENSE](https://github.com/PassiveLogic/swift-dispatch-async/blob/main/LICENSE) for full terms of use. | ||
| 
     | 
||
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.