{"id":18060173,"url":"https://github.com/fatbobman/modelactorx","last_synced_at":"2025-08-19T04:31:38.966Z","repository":{"id":260221593,"uuid":"880652870","full_name":"fatbobman/ModelActorX","owner":"fatbobman","description":"ModelActorX is a Swift library that provides custom macros ModelActorX and MainModelActorX to enhance and extend the functionality of SwiftData's ModelActor.","archived":false,"fork":false,"pushed_at":"2024-11-01T07:10:33.000Z","size":19,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-18T18:13:05.125Z","etag":null,"topics":["coredata","swift","swiftdata","swiftui"],"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/fatbobman.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}},"created_at":"2024-10-30T05:16:02.000Z","updated_at":"2024-11-13T11:43:22.000Z","dependencies_parsed_at":"2024-10-30T08:53:56.140Z","dependency_job_id":null,"html_url":"https://github.com/fatbobman/ModelActorX","commit_stats":null,"previous_names":["fatbobman/modelactorx"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FModelActorX","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FModelActorX/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FModelActorX/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FModelActorX/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fatbobman","download_url":"https://codeload.github.com/fatbobman/ModelActorX/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230318624,"owners_count":18207812,"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":["coredata","swift","swiftdata","swiftui"],"created_at":"2024-10-31T04:06:17.831Z","updated_at":"2024-12-18T18:13:09.124Z","avatar_url":"https://github.com/fatbobman.png","language":"Swift","funding_links":["https://buymeacoffee.com/fatbobman"],"categories":[],"sub_categories":[],"readme":"# ModelActorX\n\n![Swift 6](https://img.shields.io/badge/Swift-6-orange?logo=swift) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\nModelActorX is a Swift library that provides custom macros `ModelActorX` and `MainModelActorX` to enhance and extend the functionality of SwiftData's `ModelActor`. These macros offer additional flexibility by allowing developers to control the generation of initializers and to declare additional variables within actors and classes.\n\n---\n\nDon't miss out on the latest updates and excellent articles about Swift, SwiftUI, Core Data, and SwiftData. Subscribe to **[Fatbobman's Swift Weekly](https://weekly.fatbobman.com)** and receive weekly insights and valuable content directly to your inbox.\n\n---\n\n## Features\n\n- **ModelActorX Macro**: Similar to SwiftData's `ModelActor`, with an added `disableGenerateInit` parameter to control initializer generation.\n- **MainModelActorX Macro**: Generates a class running on the `MainActor`, ideal for main-thread operations, and uses `ModelContainer`'s `mainContext`. \n- **Custom Initializers**: Ability to declare additional variables and pass them through custom initializers when `disableGenerateInit` is set to `true`.\n- **Seamless Integration**: Designed to work seamlessly with SwiftData and existing Swift projects.\n\n## Installation\n\n### Swift Package Manager\n\nAdd ModelActorX to your project using Swift Package Manager. In your `Package.swift` file, add:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/fatbobman/ModelActorX.git\", from: \"0.1.0\")\n]\n```\n\nAlternatively, in Xcode:\n\n1. Go to **File** \u003e **Add Packages...**\n2. Enter the repository URL: `https://github.com/fatbobman/ModelActorX.git`\n3. Follow the prompts to add the package to your project.\n\n## Usage\n\n### ModelActorX\n\nThe `ModelActorX` macro is used to define an actor with functionality similar to SwiftData's `ModelActor`. The key difference is the `disableGenerateInit` parameter, which, when set to `true`, prevents the automatic generation of an initializer. This allows you to declare additional variables and provide a custom initializer.\n\n#### Basic Usage\n\n```swift\n@ModelActorX\nactor DataHandler {\n    func newItem(date: Date) throws -\u003e PersistentIdentifier {\n        let item = Item(timestamp: date)\n        modelContext.insert(item)\n        try modelContext.save()\n        return item.persistentModelID\n    }\n\n    func getTimestampFromItemID(_ itemID: PersistentIdentifier) -\u003e Date? {\n        return self[itemID, as: Item.self]?.timestamp\n    }\n}\n```\n\n#### Custom Initializer\n\n```swift\n@ModelActorX(disableGenerateInit: true)\nactor DataHandler1 {\n    let date: Date\n\n    func newItem() throws -\u003e PersistentIdentifier {\n        let item = Item(timestamp: date)\n        modelContext.insert(item)\n        try modelContext.save()\n        return item.persistentModelID\n    }\n\n    func getTimestampFromItemID(_ itemID: PersistentIdentifier) -\u003e Date? {\n        return self[itemID, as: Item.self]?.timestamp\n    }\n\n    init(container: ModelContainer, date: Date) {\n        self.date = date\n        modelContainer = container\n        let modelContext = ModelContext(modelContainer)\n        modelExecutor = DefaultSerialModelExecutor(modelContext: modelContext)\n    }\n}\n```\n\n### MainModelActorX\n\nThe `MainModelActorX` macro is used to generate a class that runs on the `MainActor`. This is particularly useful for UI updates or any operations that need to be performed on the main thread. The generated class uses the `mainContext` from `ModelContainer`.\n\n#### Basic Usage\n\n```swift\n@MainActor\n@MainModelActorX\nfinal class MainDataHandler {\n    func newItem(date: Date) throws -\u003e PersistentIdentifier {\n        let item = Item(timestamp: date)\n        modelContext.insert(item)\n        try modelContext.save()\n        return item.persistentModelID\n    }\n\n    func getTimestampFromItemID(_ itemID: PersistentIdentifier) -\u003e Date? {\n        return self[itemID, as: Item.self]?.timestamp\n    }\n}\n```\n\n#### Custom Initializer\n\n```swift\n@MainActor\n@MainModelActorX(disableGenerateInit: true)\nfinal class MainDataHandler1 {\n    let date: Date\n\n    func newItem() throws -\u003e PersistentIdentifier {\n        let item = Item(timestamp: date)\n        modelContext.insert(item)\n        try modelContext.save()\n        return item.persistentModelID\n    }\n\n    func getTimestampFromItemID(_ itemID: PersistentIdentifier) -\u003e Date? {\n        return self[itemID, as: Item.self]?.timestamp\n    }\n\n    init(container: ModelContainer, date: Date) {\n        self.date = date\n        modelContainer = container\n    }\n}\n```\n\n### Using ModelActorX with MainActor\n\n`@ModelActorX` also provides a constructor declared with `@MainActor`. When you use this constructor to generate an actor, it will directly utilize the `mainContext` (view context), and the entire actor will run on the main thread. The key difference from `@MainModelActorX` is that the type remains an `actor`. This means that existing code built upon ModelActor does not require modification—the calls will still retain `await`.\n\nThis approach might be an ideal temporary solution before iOS 18 addresses the responsiveness issues related to updates using `@ModelActor`.\n\n```swift\n@ModelActorX\nactor DataHandler {}\n\nTask{ @MainActor in\n   let handler = DataHandler(mainContext: container.mainContext) // Use the view context for construction\n   await handler.updateItem(id: id) // Even on the main thread, you can still use `await`\n}\n```\n\n## Testing Examples\n\n### ModelActorXTests\n\n```swift\nstruct ModelActorXTests {\n    @Test func example1() async throws {\n        let container = createContainer()\n        let handler = DataHandler(modelContainer: container)\n        let now = Date.now\n        let id = try await handler.newItem(date: now)\n        let date = await handler.getTimestampFromItemID(id)\n        #expect(date == now)\n    }\n\n    @Test func example2() async throws {\n        let container = createContainer()\n        let now = Date.now\n        let handler = DataHandler1(container: container, date: now)\n        let id = try await handler.newItem()\n        let date = await handler.getTimestampFromItemID(id)\n        #expect(date == now)\n    }\n}\n```\n\n### MainModelActorXTests\n\n```swift\n@MainActor\nstruct MainModelActorXTests {\n    @Test\n    func test1() async throws {\n        let container = createContainer()\n        let handler = MainDataHandler(modelContainer: container)\n        let now = Date.now\n        let id = try handler.newItem(date: now)\n        let date = handler.getTimestampFromItemID(id)\n        #expect(date == now)\n    }\n\n    @Test\n    func test2() async throws {\n        let container = createContainer()\n        let now = Date.now\n        let handler = MainDataHandler1(container: container, date: now)\n        let id = try handler.newItem()\n        let date = handler.getTimestampFromItemID(id)\n        #expect(date == now)\n    }\n}\n```\n\n## Parameters\n\n### ModelActorX Macro\n\n- `disableGenerateInit: Bool` (optional): Controls whether an initializer is automatically generated. Default is `false`.\n\n### MainModelActorX Macro\n\n- `disableGenerateInit: Bool` (optional): Controls whether an initializer is automatically generated. Default is `false`.\n\n## Requirements\n\n- Swift 6\n- iOS 17.0 / macOS 14 / tvOS 17 / watchOS 10 or later\n\n## License\n\nModelActorX is released under the MIT License. See [LICENSE](LICENSE) for details.\n\n## Acknowledgements\n\n- Inspired by SwiftData's `ModelActor` functionality.\n- Core Data Version: [CoreDataEvolution](https://github.com/fatbobman/CoreDataEvolution)\n- Thanks to the Swift community for continuous support and contributions.\n\n## Contributing\n\nContributions are welcome! If you have ideas for improvements or find bugs, please open an issue or submit a pull request.\n\n[![Buy Me A Coffee](https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png)](https://buymeacoffee.com/fatbobman)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffatbobman%2Fmodelactorx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffatbobman%2Fmodelactorx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffatbobman%2Fmodelactorx/lists"}