{"id":19685877,"url":"https://github.com/rxswiftcommunity/action","last_synced_at":"2025-05-15T15:07:27.874Z","repository":{"id":45920525,"uuid":"46382724","full_name":"RxSwiftCommunity/Action","owner":"RxSwiftCommunity","description":"Abstracts actions to be performed in RxSwift.","archived":false,"fork":false,"pushed_at":"2023-10-17T20:06:12.000Z","size":898,"stargazers_count":877,"open_issues_count":26,"forks_count":150,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-05-09T17:48:56.931Z","etag":null,"topics":["hacktoberfest","reactive-extensions","rxswift"],"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/RxSwiftCommunity.png","metadata":{"files":{"readme":"Readme.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"License.md","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":"2015-11-17T23:42:31.000Z","updated_at":"2025-04-28T06:43:19.000Z","dependencies_parsed_at":"2024-06-18T12:15:16.893Z","dependency_job_id":"13dc5a92-b9b1-41e0-811d-50a975673b72","html_url":"https://github.com/RxSwiftCommunity/Action","commit_stats":{"total_commits":391,"total_committers":54,"mean_commits":"7.2407407407407405","dds":0.7749360613810742,"last_synced_commit":"90259f7462a07e8f26bc8300ea16bcdf73ca7827"},"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RxSwiftCommunity%2FAction","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RxSwiftCommunity%2FAction/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RxSwiftCommunity%2FAction/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RxSwiftCommunity%2FAction/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RxSwiftCommunity","download_url":"https://codeload.github.com/RxSwiftCommunity/Action/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254364270,"owners_count":22058878,"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":["hacktoberfest","reactive-extensions","rxswift"],"created_at":"2024-11-11T18:24:30.514Z","updated_at":"2025-05-15T15:07:22.865Z","avatar_url":"https://github.com/RxSwiftCommunity.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/RxSwiftCommunity/Action/actions/workflows/ci.yml/badge.svg)](https://github.com/RxSwiftCommunity/Action/actions/workflows/ci.yml)\n\nAction\n======\n\nThis library is used with [RxSwift](https://github.com/ReactiveX/RxSwift) to provide an abstraction on top of observables: actions.\n\nAn action is a way to say \"hey, later I'll need you to subscribe to this thing.\" It's actually a lot more involved than that.\n\nActions accept a `workFactory`: a closure that takes some input and produces an observable. When `execute()` is called on the action, the `workFactory` gets passed this parameter and the action subscribes to the observable that gets returned.\n\nAn action:\n\n- Can only be executed while \"enabled\" (`true` if unspecified).\n- Only executes one thing at a time.\n- Aggregates next/error events across individual executions.\n\nOh, and it has this really Swift thing with `UIButton` that's pretty cool. It'll manage the button's enabled state, make sure the button is disabled while your work is being done, all that stuff 👍\n\nUsage\n-----\n\nYou have to pass a `workFactory` that takes input and returns an `Observable`. This represents some work that needs to be accomplished. Whenever you call `execute()`, you pass in input that's fed to the work factory. The `Action` will subscribe to the observable and emit the `Next` events on its `elements` property. If the observable errors, the error is sent as a `Next` even on the `errors` property. Neat.\n\nActions can only execute one thing at a time. If you try to execute an action that's currently executing, you'll get an error. The `executing` property sends `true` and `false` values as `Next` events.\n\n```swift\naction: Action\u003cString, Bool\u003e = Action(workFactory: { input in\n    return networkLibrary.checkEmailExists(input)\n})\n\n...\n\naction.execute(\"ash@ashfurrow.com\")\n```\n\nNotice that the first generic parameter is the type of the input, and the second is the type of observable that `workFactory` creates. You can think of it a bit like the action's \"output.\"\n\nYou can also specify an `enabledIf` parameter to the `Action` initializer.\n\n```swift\nlet validEmailAddress = emailTextField.rx.text.map(isValidEmail)\n\naction: Action\u003cString, Bool\u003e = Action(enabledIf: validEmailAddress, workFactory: { input in\n    return networkLibrary.checkEmailExists(input)\n})\n```\n\nNow `execute()` only does the work if the email address is valid. Super cool!\n\n(Note that `enabledIf` isn't the same as the `enabled` property. You pass in `enabledIf` and the action uses that (combined with its current executing state) to determine if it's currently enabled.)\n\nWhat's _really_ cool is the `UIButton` extension. It accepts a `CocoaAction`, which is just `Action\u003cVoid, Void\u003e`.\n\n```swift\nbutton.rx.action = action\n```\n\nNow when the button is pressed, the action is executed. The button's `enabled` state is bound to the action's `enabled` property. That means you can feed your form-validation logic into the action as a signal, and your button's enabled state is handled for you. Also, the user can't press the button again before the action is done executing, since it only handles one thing at a time. Cool. Check out [this code example of CocoaAction _in_ action](https://github.com/artsy/eidolon/blob/cb31168fa29dcc7815fd4a2e30e7c000bd1820ce/Kiosk/Bid%20Fulfillment/GenericFormValidationViewModel.swift).\n\nIf you'd like to use `Action` to do a complex operation such as file download with download progress report (to update progress bar in the UI for example) you'd use `Action\u003cVoid, Int\u003e` instead of `CocoaAction`. Out of the box `CocoaAction` can't emit progress values, your own `Action\u003cVoid, Int\u003e` will do that. For details refer to [this article](http://www.sm-cloud.com/rxswift-action/).\n\nIf your scenario involves many buttons that needs to trigger the same `Action` providing different input, you can use `bindTo` on each `UIButton` with a closure that returns correct input.\n\n```swift\nlet button1 = UIButton()\nlet button2 = UIButton()\n\nlet action = Action\u003cString, String\u003e { input in\n    print(input)\n    return .just(input)\n}\nbutton1.rx.bindTo(action) { _ in return \"Hello\"}\nbutton2.rx.bindTo(action) { _ in return \"Goodbye\"}\n```\n\n`button1` and `button2` are sharing the same `Action`, but they are feeding it with different input (`Hello` and `Goodbye` that will be printed for corresponding tap).\n\nA more complex use case can be a single action related to a `UIViewController` that manages your navigation, error handling and loading state. With this approach, you can have as many `UIButton`s (or `UIBarButtonItem`s) as you want and subscribe to `executing`, `errors`, `elements` and `completions` once and in a single common place.\n\nThere's also a really cool extension on `UIAlertAction`, used by [`UIAlertController`](http://ashfurrow.com/blog/uialertviewcontroller-example/). One catch: because of the limitations of that class, you can't instantiate it with the normal initializer. Instead, call this class method:\n\n```swift\nlet action = UIAlertAction.Action(\"Hi\", style: .default)\n```\n\nInstalling\n----------\n\n### CocoaPods\n\nJust add the line below to your Podfile:\n\n```ruby\npod 'Action'\n```\n\nThen run `pod install` and that'll be 👌\n\n### Carthage\n\nAdd this to `Cartfile`\n\n```\ngithub \"RxSwiftCommunity/Action\" ~\u003e 5.0.0\n```\n\nIf you are using RxSwift 3.2.0 or below, Use Action `~2.2.0` instead!\n\nthen run\n\n```sh\n\u003e carthage update\n```\n\nThanks\n------\n\nThis library is (pretty obviously) inspired by [ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa)'s [`Action` class](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/ReactiveCocoa/Swift/Action.swift). Those developers deserve a lot of thanks!\n\nLicense\n-------\n\nMIT obvs.\n\n![Permissive licenses are the only licenses permitted in the Q continuum.](https://38.media.tumblr.com/4ca19ffae09cb09520cbb5611f0a17e9/tumblr_n13vc9nm1Q1svlvsyo6_250.gif)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frxswiftcommunity%2Faction","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frxswiftcommunity%2Faction","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frxswiftcommunity%2Faction/lists"}