{"id":16487227,"url":"https://github.com/nerdsupremacist/sync","last_synced_at":"2025-07-22T22:33:45.469Z","repository":{"id":41109535,"uuid":"446980000","full_name":"nerdsupremacist/Sync","owner":"nerdsupremacist","description":"Real-time Apps the SwiftUI way","archived":false,"fork":false,"pushed_at":"2022-06-19T18:21:27.000Z","size":655,"stargazers_count":160,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-01T23:51:30.549Z","etag":null,"topics":["real-time","state","swift","swiftui","sync","websocket"],"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/nerdsupremacist.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-11T21:02:24.000Z","updated_at":"2025-03-22T23:03:10.000Z","dependencies_parsed_at":"2022-08-28T23:31:18.953Z","dependency_job_id":null,"html_url":"https://github.com/nerdsupremacist/Sync","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/nerdsupremacist/Sync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FSync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FSync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FSync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FSync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nerdsupremacist","download_url":"https://codeload.github.com/nerdsupremacist/Sync/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FSync/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266585943,"owners_count":23952168,"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","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["real-time","state","swift","swiftui","sync","websocket"],"created_at":"2024-10-11T13:33:16.344Z","updated_at":"2025-07-22T22:33:45.432Z","avatar_url":"https://github.com/nerdsupremacist.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"logo.png\" width=\"600\" max-width=\"90%\" alt=\"Sync\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Swift-5.5-orange.svg\" /\u003e\n    \u003ca href=\"https://swift.org/package-manager\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/swiftpm-compatible-brightgreen.svg?style=flat\" alt=\"Swift Package Manager\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://twitter.com/nerdsupremacist\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/twitter-@nerdsupremacist-blue.svg?style=flat\" alt=\"Twitter: @nerdsupremacist\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n# Sync\nSync is a proof of concept for expanding on the Magic of ObservableObject, and making it work over the network. \nThis let's you create real-time Apps in which your Observable Objects are in sync across multiple devices.\nThis has a lot of applications just as:\n- IoT Apps\n- Multi-Player Mini Games\n- etc.\n\nAs of right now Sync works out of the box using WebSockets, however, it's not limited to web sockets and it allows for multiple kinds of connections. Some possible connections could be:\n- Bluetooth\n- Multi-Peer\n- MQTT\n- etc.\n\nThe sky is the limit!\n\n**Warning:** This is only a proof of concept that I'm using for experimentation. I assume there's lots and lots of bugs in there...\n\n## Installation\n### Swift Package Manager\n\nYou can install Sync via [Swift Package Manager](https://swift.org/package-manager/) by adding the following line to your `Package.swift`:\n\n```swift\nimport PackageDescription\n\nlet package = Package(\n    [...]\n    dependencies: [\n        .package(url: \"https://github.com/nerdsupremacist/Sync.git\", from: \"1.0.0\")\n    ]\n)\n```\n\n## Usage\n\nIf you have ever used Observable Object, then Sync will be extremely easy to use. \nFor this example we will create an app with a Switch that everyone can flip on or off as they like. We will build this using SwiftUI, WebSockets and a Vapor Server. Final code available [here](https://github.com/nerdsupremacist/SyncExampleApp).\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"demo.gif\" width=\"600\" max-width=\"90%\" alt=\"Sync\" /\u003e\n\u003c/p\u003e\n\nFor this we will need a few additional packages:\n- [Vapor](https://vapor.codes): To create a Web Server that will sync our devices\n- [SyncWebSocketClient](https://github.com/nerdsupremacist/SyncWebSocketClient): The client code for using WebSockets\n- [SyncWebSocketVapor](https://github.com/nerdsupremacist/SyncWebSocketVapor): A utility to make it easy to serve our object via a WebSocket\n\nLet's start by building our shared ViewModel. This is easy, instead of using `ObservableObject` we use `SyncableObject`. And instead of `Published` we use `Synced`:\n```swift\nclass ViewModel: SyncableObject {\n    @Synced\n    var toggle: Bool = false\n\n    init() { }\n}\n```\n\nThis ViewModel needs to be both on your App codebase as well as on the Server codebase. I recommend putting it in a shared Swift Package, if you're feeling fancy.\n\nNext stop is to create our server. In this example every client will be using the exact same ViewModel. So we're creating a Vapor application, and using `syncObjectOverWebSocket` to provide the object:\n\n```swift\nimport Vapor\nimport SyncWebSocketVapor\n\nlet app = Application(try .detect())\n\nlet viewModel = ViewModel()\napp.syncObjectOverWebSocket(\"view_model\") { _ in\n    return viewModel\n}\n\ntry app.run()\n```\n\nFor our SwiftUI App, we need to use two things:\n- @SyncedObject: Like [ObservedObject](https://developer.apple.com/documentation/swiftui/observedobject), but for Syncable Objects. It's a property wrapper that will dynamically tell SwiftUI when to update the UI\n- Sync: A little wrapper view to start the remote session\n\nOur actual view then uses SyncedObservedObject with our ViewModel\n```swift\nstruct ContentView: View {\n    @SyncedObject\n    var viewModel: ViewModel\n\n    var body: some View {\n        Toggle(\"A toggle\", isOn: $viewModel.toggle)\n            .animation(.easeIn, value: viewModel.toggle)\n            .padding(64)\n    }\n}\n```\n\nAnd in order to display it we use Sync, and pass along the Web Socket Connection:\n```swift\nstruct RootView: View {\n    var body: some View {\n        Sync(ViewModel.self, using: .webSocket(url: url)) { viewModel in\n            ContentView(viewModel: viewModel)\n        }\n    }\n}\n```\n\n### Developing for Web?\n\nNo problem. You can scale this solution to the web using [Tokamak](https://github.com/TokamakUI/Tokamak), and use the same UI on the Web thanks to Web Assembly.\nHere are the Web Assembly specific packages for Sync:\n- [SyncTokamak](https://github.com/nerdsupremacist/SyncTokamak): Compatibility Layer so that Tokamak reacts to updates\n- [SyncWebSocketWebAssemblyClient](https://github.com/nerdsupremacist/SyncWebSocketWebAssemblyClient): Web Assembly compatible version of [SyncWebSocketClient](https://github.com/nerdsupremacist/SyncWebSocketClient)\n\nHere's a small demo of that working:\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/nerdsupremacist/SyncTokamak/raw/main/demo.gif\" width=\"600\" max-width=\"90%\" alt=\"Sync\" /\u003e\n\u003c/p\u003e\n\n## Contributions\nContributions are welcome and encouraged!\n\n## License\nSync is available under the MIT license. See the LICENSE file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnerdsupremacist%2Fsync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnerdsupremacist%2Fsync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnerdsupremacist%2Fsync/lists"}