{"id":15862477,"url":"https://github.com/nghialv/reactivecocoa","last_synced_at":"2025-04-01T20:44:29.862Z","repository":{"id":150607956,"uuid":"60915370","full_name":"nghialv/ReactiveCocoa","owner":"nghialv","description":"A repo for storing ReactiveCocoa's podspec","archived":false,"fork":false,"pushed_at":"2016-06-15T02:47:26.000Z","size":1680,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-07T13:33:29.484Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nghialv.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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":"2016-06-11T16:03:38.000Z","updated_at":"2018-12-16T11:19:18.000Z","dependencies_parsed_at":"2023-04-29T12:31:43.315Z","dependency_job_id":null,"html_url":"https://github.com/nghialv/ReactiveCocoa","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nghialv%2FReactiveCocoa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nghialv%2FReactiveCocoa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nghialv%2FReactiveCocoa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nghialv%2FReactiveCocoa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nghialv","download_url":"https://codeload.github.com/nghialv/ReactiveCocoa/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246709918,"owners_count":20821298,"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":[],"created_at":"2024-10-05T22:40:59.921Z","updated_at":"2025-04-01T20:44:29.846Z","avatar_url":"https://github.com/nghialv.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"![](Logo/header.png)\n\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![GitHub release](https://img.shields.io/github/release/ReactiveCocoa/ReactiveCocoa.svg)](https://github.com/ReactiveCocoa/ReactiveCocoa/releases) ![Swift 2.2.x](https://img.shields.io/badge/Swift-2.2.x-orange.svg) ![platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20OS%20X%20%7C%20watchOS%20%7C%20tvOS%20-lightgrey.svg)\n\nReactiveCocoa (RAC) is a Cocoa framework inspired by [Functional Reactive Programming](https://en.wikipedia.org/wiki/Functional_reactive_programming). It provides APIs for composing and transforming **streams of values over time**.\n\n 1. [Introduction](#introduction)\n 1. [Example: online search](#example-online-search)\n 1. [Objective-C and Swift](#objective-c-and-swift)\n 1. [How does ReactiveCocoa relate to Rx?](#how-does-reactivecocoa-relate-to-rx)\n 1. [Getting started](#getting-started)\n 1.  [Playground](#playground)\n\nIf you’re already familiar with functional reactive programming or what\nReactiveCocoa is about, check out the [Documentation][] folder for more in-depth\ninformation about how it all works. Then, dive straight into our [documentation\ncomments][Code] for learning more about individual APIs.\n\nIf you have a question, please see if any discussions in our [GitHub\nissues](https://github.com/ReactiveCocoa/ReactiveCocoa/issues?q=is%3Aissue+label%3Aquestion+) or [Stack\nOverflow](http://stackoverflow.com/questions/tagged/reactive-cocoa) have already\nanswered it. If not, please feel free to [file your\nown](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/new)!\n\n#### Compatibility\n\nThis documents the RAC 4 which targets `Swift 2.2.x`. For `Swift 1.2` support see [RAC\n3](https://github.com/ReactiveCocoa/ReactiveCocoa/tree/v3.0.0).\n\n## Introduction\n\nReactiveCocoa is inspired by [functional reactive\nprogramming](http://blog.maybeapps.com/post/42894317939/input-and-output).\nRather than using mutable variables which are replaced and modified in-place,\nRAC offers “event streams,” represented by the [`Signal`][Signals] and\n[`SignalProducer`][Signal producers] types, that send values over time.\n\nEvent streams unify all of Cocoa’s common patterns for asynchrony and event\nhandling, including:\n\n * Delegate methods\n * Callback blocks\n * `NSNotification`s\n * Control actions and responder chain events\n * [Futures and promises](https://en.wikipedia.org/wiki/Futures_and_promises)\n * [Key-value observing](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html) (KVO)\n\nBecause all of these different mechanisms can be represented in the _same_ way,\nit’s easy to declaratively chain and combine them together, with less spaghetti\ncode and state to bridge the gap.\n\nFor more information about the concepts in ReactiveCocoa, see the [Framework\nOverview][].\n\n## Example: online search\n\nLet’s say you have a text field, and whenever the user types something into it,\nyou want to make a network request which searches for that query.\n\n#### Observing text edits\n\nThe first step is to observe edits to the text field, using a RAC extension to\n`UITextField` specifically for this purpose:\n\n```swift\nlet searchStrings = textField.rac_textSignal()\n    .toSignalProducer()\n    .map { text in text as! String }\n```\n\nThis gives us a [signal producer][Signal producers] which sends\nvalues of type `String`. _(The cast is [currently\nnecessary](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2182) to bridge\nthis extension method from Objective-C.)_\n\n#### Making network requests\n\nWith each string, we want to execute a network request. Luckily, RAC offers an\n`NSURLSession` extension for doing exactly that:\n\n```swift\nlet searchResults = searchStrings\n    .flatMap(.Latest) { (query: String) -\u003e SignalProducer\u003c(NSData, NSURLResponse), NSError\u003e in\n        let URLRequest = self.searchRequestWithEscapedQuery(query)\n        return NSURLSession.sharedSession().rac_dataWithRequest(URLRequest)\n    }\n    .map { (data, URLResponse) -\u003e String in\n        let string = String(data: data, encoding: NSUTF8StringEncoding)!\n        return self.parseJSONResultsFromString(string)\n    }\n    .observeOn(UIScheduler())\n```\n\nThis has transformed our producer of `String`s into a producer of `Array`s\ncontaining the search results, which will be forwarded on the main thread\n(thanks to the [`UIScheduler`][Schedulers]).\n\nAdditionally, [`flatMap(.Latest)`][flatMapLatest] here ensures that _only one search_—the\nlatest—is allowed to be running. If the user types another character while the\nnetwork request is still in flight, it will be cancelled before starting a new\none. Just think of how much code that would take to do by hand!\n\n#### Receiving the results\n\nThis won’t actually execute yet, because producers must be _started_ in order to\nreceive the results (which prevents doing work when the results are never used).\nThat’s easy enough:\n\n```swift\nsearchResults.startWithNext { results in\n    print(\"Search results: \\(results)\")\n}\n```\n\nHere, we watch for the `Next` [event][Events], which contains our results, and\njust log them to the console. This could easily do something else instead, like\nupdate a table view or a label on screen.\n\n#### Handling failures\n\nIn this example so far, any network error will generate a `Failed`\n[event][Events], which will terminate the event stream. Unfortunately, this\nmeans that future queries won’t even be attempted.\n\nTo remedy this, we need to decide what to do with failures that occur. The\nquickest solution would be to log them, then ignore them:\n\n```swift\n    .flatMap(.Latest) { (query: String) -\u003e SignalProducer\u003c(NSData, NSURLResponse), NSError\u003e in\n        let URLRequest = self.searchRequestWithEscapedQuery(query)\n\n        return NSURLSession.sharedSession()\n            .rac_dataWithRequest(URLRequest)\n            .flatMapError { error in\n                print(\"Network error occurred: \\(error)\")\n                return SignalProducer.empty\n            }\n    }\n```\n\nBy replacing failures with the `empty` event stream, we’re able to effectively\nignore them.\n\nHowever, it’s probably more appropriate to retry at least a couple of times\nbefore giving up. Conveniently, there’s a [`retry`][retry] operator to do exactly that!\n\nOur improved `searchResults` producer might look like this:\n\n```swift\nlet searchResults = searchStrings\n    .flatMap(.Latest) { (query: String) -\u003e SignalProducer\u003c(NSData, NSURLResponse), NSError\u003e in\n        let URLRequest = self.searchRequestWithEscapedQuery(query)\n\n        return NSURLSession.sharedSession()\n            .rac_dataWithRequest(URLRequest)\n            .retry(2)\n            .flatMapError { error in\n                print(\"Network error occurred: \\(error)\")\n                return SignalProducer.empty\n            }\n    }\n    .map { (data, URLResponse) -\u003e String in\n        let string = String(data: data, encoding: NSUTF8StringEncoding)!\n        return self.parseJSONResultsFromString(string)\n    }\n    .observeOn(UIScheduler())\n```\n\n#### Throttling requests\n\nNow, let’s say you only want to actually perform the search periodically,\nto minimize traffic.\n\nReactiveCocoa has a declarative `throttle` operator that we can apply to our\nsearch strings:\n\n```swift\nlet searchStrings = textField.rac_textSignal()\n    .toSignalProducer()\n    .map { text in text as! String }\n    .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)\n```\n\nThis prevents values from being sent less than 0.5 seconds apart.\n\nTo do this manually would require significant state, and end up much harder to\nread! With ReactiveCocoa, we can use just one operator to incorporate _time_ into\nour event stream.\n\n#### Debugging event streams\n\nDue to its nature, a stream's stack trace might have dozens of frames, which, more often than not, can make debugging a very frustrating activity. \nA naive way of debugging, is by injecting side effects into the stream, like so:\n\n```swift\nlet searchString = textField.rac_textSignal()\n    .toSignalProducer()\n    .map { text in text as! String }\n    .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)\n    .on(event: { print ($0) }) // the side effect\n```\n\nThis will print the stream's [events][Events], while preserving the original stream behaviour. Both [`SignalProducer`][Signal producers]\nand [`Signal`][Signals] provide the `logEvents` operator, that will do this automatically for you:\n\n```swift\nlet searchString = textField.rac_textSignal()\n    .toSignalProducer()\n    .map { text in text as! String }\n    .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)\n    .logEvents()\n```\n\nFor more information and advance usage, check the [Debugging Techniques](Documentation/DebuggingTechniques.md) document.\n\n\n## Objective-C and Swift\n\nAlthough ReactiveCocoa was started as an Objective-C framework, as of [version\n3.0][CHANGELOG], all major feature development is concentrated on the [Swift API][].\n\nRAC’s [Objective-C API][] and Swift API are entirely separate, but there is\na [bridge][Objective-C Bridging] to convert between the two. This\nis mostly meant as a compatibility layer for older ReactiveCocoa projects, or to\nuse Cocoa extensions which haven’t been added to the Swift API yet.\n\nThe Objective-C API will continue to exist and be supported for the foreseeable\nfuture, but it won’t receive many improvements. For more information about using\nthis API, please consult our [legacy documentation][].\n\n**We highly recommend that all new projects use the Swift API.**\n\n## How does ReactiveCocoa relate to Rx?\n\nReactiveCocoa was originally inspired, and therefore heavily influenced, by\nMicrosoft’s [Reactive\nExtensions](https://msdn.microsoft.com/en-us/data/gg577609.aspx) (Rx) library. There are many ports of Rx, including [RxSwift](https://github.com/ReactiveX/RxSwift), but ReactiveCocoa is _intentionally_ not a direct port.\n\n**Where RAC differs from Rx**, it is usually to:\n\n * Create a simpler API\n * Address common sources of confusion\n * More closely match Cocoa conventions\n\nThe following are some of the concrete differences, along with their rationales.\n\n### Naming\n\nIn most versions of Rx, Streams over time are known as `Observable`s, which\nparallels the `Enumerable` type in .NET. Additionally, most operations in Rx.NET\nborrow names from [LINQ](https://msdn.microsoft.com/en-us/library/bb397926.aspx),\nwhich uses terms reminiscent of relational databases, like `Select` and `Where`.\n\n**RAC is focused on matching Swift naming first and foremost**, with terms like\n`map` and `filter` instead. Other naming differences are typically inspired by\nsignificantly better alternatives from [Haskell](https://www.haskell.org) or\n[Elm](http://elm-lang.org) (which is the primary source for the “signal”\nterminology).\n\n### Signals and Signal Producers (“hot” and “cold” observables)\n\nOne of the most confusing aspects of Rx is that of [“hot”, “cold”, and “warm”\nobservables](http://www.introtorx.com/content/v1.0.10621.0/14_HotAndColdObservables.html) (event streams).\n\nIn short, given just a method or function declaration like this, in C#:\n\n```csharp\nIObservable\u003cstring\u003e Search(string query)\n```\n\n… it is **impossible to tell** whether subscribing to (observing) that\n`IObservable` will involve side effects. If it _does_ involve side effects, it’s\nalso impossible to tell whether _each subscription_ has a side effect, or if only\nthe first one does.\n\nThis example is contrived, but it demonstrates **a real, pervasive problem**\nthat makes it extremely hard to understand Rx code (and pre-3.0 ReactiveCocoa\ncode) at a glance.\n\n[ReactiveCocoa 3.0][CHANGELOG] has solved this problem by distinguishing side\neffects with the separate [`Signal`][Signals] and [`SignalProducer`][Signal producers] types. Although this\nmeans there’s another type to learn about, it improves code clarity and helps\ncommunicates intent much better.\n\nIn other words, **ReactiveCocoa’s changes here are [simple, not\neasy](http://www.infoq.com/presentations/Simple-Made-Easy)**.\n\n### Typed errors\n\nWhen [signals][] and [signal producers][] are allowed to [fail][Events] in ReactiveCocoa,\nthe kind of error must be specified in the type system. For example,\n`Signal\u003cInt, NSError\u003e` is a signal of integer values that may fail with an error\nof type `NSError`.\n\nMore importantly, RAC allows the special type `NoError` to be used instead,\nwhich _statically guarantees_ that an event stream is not allowed to send a\nfailure. **This eliminates many bugs caused by unexpected failure events.**\n\nIn Rx systems with types, event streams only specify the type of their\nvalues—not the type of their errors—so this sort of guarantee is impossible.\n\n### UI programming\n\nRx is basically agnostic as to how it’s used. Although UI programming with Rx is\nvery common, it has few features tailored to that particular case.\n\nRAC takes a lot of inspiration from [ReactiveUI](http://reactiveui.net/),\nincluding the basis for [Actions][].\n\nUnlike ReactiveUI, which unfortunately cannot directly change Rx to make it more\nfriendly for UI programming, **ReactiveCocoa has been improved many times\nspecifically for this purpose**—even when it means diverging further from Rx.\n\n## Getting started\n\nReactiveCocoa supports `OS X 10.9+`, `iOS 8.0+`, `watchOS 2.0`, and `tvOS 9.0`.\n\nTo add RAC to your application:\n\n 1. Add the ReactiveCocoa repository as a\n    [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) of your\n    application’s repository.\n 1. Run `script/bootstrap` from within the ReactiveCocoa folder.\n 1. Drag and drop `ReactiveCocoa.xcodeproj` and `Carthage/Checkouts/Result/Result.xcodeproj`\n    into your application’s Xcode project or workspace.\n 1. On the “General” tab of your application target’s settings, add\n    `ReactiveCocoa.framework` and `Result.framework` to the “Embedded Binaries” section.\n 1. If your application target does not contain Swift code at all, you should also\n    set the `EMBEDDED_CONTENT_CONTAINS_SWIFT` build setting to “Yes”.\n\nOr, if you’re using [Carthage](https://github.com/Carthage/Carthage), simply add\nReactiveCocoa to your `Cartfile`:\n\n```\ngithub \"ReactiveCocoa/ReactiveCocoa\"\n```\nMake sure to add both `ReactiveCocoa.framework` and `Result.framework` to \"Linked Frameworks and Libraries\" and \"copy-frameworks\" Build Phases.\n\nIf you would prefer to use [CocoaPods](https://cocoapods.org), there are some\n[unofficial podspecs](https://github.com/CocoaPods/Specs/tree/master/Specs/ReactiveCocoa)\nthat have been generously contributed by third parties.\n\nOnce you’ve set up your project, check out the [Framework Overview][] for\na tour of ReactiveCocoa’s concepts, and the [Basic Operators][] for some\nintroductory examples of using it.\n\n## Playground\n\nWe also provide a great Playground, so you can get used to ReactiveCocoa's operators. In order to start using it:\n\n 1. Clone the ReactiveCocoa repository.\n 1. Retrieve the project dependencies using one of the following terminal commands from the ReactiveCocoa project root directory:\n     - `script/bootstrap` **OR**, if you have [Carthage](https://github.com/Carthage/Carthage) installed    \n     - `carthage checkout`\n 1. Open `ReactiveCocoa.xcworkspace`\n 1. Build `Result-Mac` scheme\n 1. Build `ReactiveCocoa-Mac` scheme\n 1. Finally open the `ReactiveCocoa.playground`\n 1. Choose `View \u003e Show Debug Area`\n    \n[Actions]: Documentation/FrameworkOverview.md#actions\n[Basic Operators]: Documentation/BasicOperators.md\n[CHANGELOG]: CHANGELOG.md\n[Code]: ReactiveCocoa\n[Documentation]: Documentation\n[Events]: Documentation/FrameworkOverview.md#events\n[Framework Overview]: Documentation/FrameworkOverview.md\n[Legacy Documentation]: Documentation/Legacy\n[Objective-C API]: ReactiveCocoa/Objective-C\n[Objective-C Bridging]: Documentation/ObjectiveCBridging.md\n[Schedulers]: Documentation/FrameworkOverview.md#schedulers\n[Signal producers]: Documentation/FrameworkOverview.md#signal-producers\n[Signals]: Documentation/FrameworkOverview.md#signals\n[Swift API]: ReactiveCocoa/Swift\n[flatMapLatest]: Documentation/BasicOperators.md#switching-to-the-latest\n[retry]: Documentation/BasicOperators.md#retrying\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnghialv%2Freactivecocoa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnghialv%2Freactivecocoa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnghialv%2Freactivecocoa/lists"}