{"id":13489250,"url":"https://github.com/yankodimitrov/SignalKit","last_synced_at":"2025-03-28T04:30:59.716Z","repository":{"id":62455362,"uuid":"39133723","full_name":"yankodimitrov/SignalKit","owner":"yankodimitrov","description":"SignalKit is a reactive Swift framework with focus on clean and readable API.","archived":false,"fork":false,"pushed_at":"2017-03-07T09:18:30.000Z","size":906,"stargazers_count":259,"open_issues_count":4,"forks_count":18,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-12T07:23:11.636Z","etag":null,"topics":["observer","protocol-oriented","reactive","signal","swift","unidirectional"],"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/yankodimitrov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-15T11:42:05.000Z","updated_at":"2025-01-17T15:14:32.000Z","dependencies_parsed_at":"2022-11-02T00:00:37.219Z","dependency_job_id":null,"html_url":"https://github.com/yankodimitrov/SignalKit","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yankodimitrov%2FSignalKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yankodimitrov%2FSignalKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yankodimitrov%2FSignalKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yankodimitrov%2FSignalKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yankodimitrov","download_url":"https://codeload.github.com/yankodimitrov/SignalKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245970391,"owners_count":20702401,"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":["observer","protocol-oriented","reactive","signal","swift","unidirectional"],"created_at":"2024-07-31T19:00:21.237Z","updated_at":"2025-03-28T04:30:59.396Z","avatar_url":"https://github.com/yankodimitrov.png","language":"Swift","funding_links":[],"categories":["Libs","Swift"],"sub_categories":["Events"],"readme":"\u003cimg src=\"https://raw.githubusercontent.com/yankodimitrov/SignalKit/SignalKit-4.0/Resources/logo.png\" width=\"280\" alt=\"SignalKit\"\u003e\n\n---\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n\n## Abstract\nSignalKit is a lightweight event and binding framework. The core of SignalKit is the Observable protocol. Each implementation of the Observable protocol defines the type of the observation thus an Observable can sendNext only one type of event. For example an Observable of type String can only sendNext String values.\n\nAnother key protocol is SignalType which implements Observable and Disposable. Each SignalType implementation has a property \u003ccode\u003edisposableSource: Disposable?\u003c/code\u003e which points to a Disposable that comes before the current signal.\n\nBecause SignalType implements Disposable we can use the \u003ccode\u003edisposableSource\u003c/code\u003e property to chain signal operations like map, filter and combineLatest together. Each operation returns either a new SignalType or a Disposable. When we call \u003ccode\u003edispose()\u003c/code\u003e on a SignalType it will dispose the whole chain of operations.\n\nTo store the chain of operations we can use a stored property or the \u003ccode\u003edisposeWith(container: DisposableBag) -\u003e Disposable\u003c/code\u003e method on the Disposable protocol. When DisposableBag is deinitialized it will dispose all of its items for us.\n\n```swift\nlet disposableBag = DisposableBag()\nlet userName = Signal\u003cString\u003e()\n\nuserName.next { print(\"name: \\($0)\") }\n\t.disposeWith(disposableBag)\n\nuserName.sendNext(\"John\") // prints \"name: John\"\n```\n\n![SignalKit Primary Protocols](https://raw.githubusercontent.com/yankodimitrov/SignalKit/SignalKit-4.0/Resources/primary-protocols.png)\n\n## Events And Bindings\n\nSignalKit comes with an elegant way to observe for different event sources like **KVO**, **Target Action** and **NSNotificationCenter** via an unified API by simply calling \u003ccode\u003eobserve()\u003c/code\u003e method. The observe method is a protocol extension on the \u003ccode\u003eNSObjectProtocol\u003c/code\u003e which returns a SignalEvent with sender Self. Then we use Protocol Oriented Programming to add extensions to a SignalEventType protocol where Sender is from a given type.\n\n![SignalKit Primary Protocols](https://raw.githubusercontent.com/yankodimitrov/SignalKit/SignalKit-4.0/Resources/event-model.png)\n\n### Key Value Observing\n\nLet's say we want to observe an instance of \u003ccode\u003eclass Person: NSObject\u003c/code\u003e for it's \u003ccode\u003ename\u003c/code\u003e property changes with KVO. This is super easy with SignalKit, just call \u003ccode\u003eobserve()\u003c/code\u003e on the instance and it will return the available events for this type. Then choose \u003ccode\u003ekeyPath(path: String, value: T)\u003c/code\u003e where for the value parameter pass the initial value of the property. SignalKit will use this initial value type to perform an optional type cast on the values sent by KVO.\n\n```swift\nlet person = Person(name: \"John\")\n\nperson.observe()\n    .keyPath(\"name\", value: person.name)\n    .next { print(\"Hello \\($0)\") }\n    .disposeWith(disposableBag)\n```\n\n### Target Action\n\nSignalKit comes with SignalEventType extensions for controls which inherits from \u003ccode\u003eUIControl\u003c/code\u003e and \u003ccode\u003eUIBarButtonItem\u003c/code\u003e:\n\n```swift\nlet control = UIControl()\nlet barButton = UIBarButtonItem()\n\ncontrol.observe().events([.TouchUpInside])\n    .next { _ in print(\"Tap!\") }\n    .disposeWith(disposableBag)\n        \nbarButton.observe().tapEvent\n    .next { _ in print(\"Tap!\") }\n    .disposeWith(disposableBag)\n```\n\n### NSNotificationCenter\n\nSignalEventType also have a handy extensions for observing an instance of \u003ccode\u003eNSNotificationCenter\u003c/code\u003e for notifications:\n\n```swift\nlet center = NSNotificationCenter.defaultCenter()\n\ncenter.observe().notification(UIApplicationWillResignActiveNotification)\n    .next{ _ in print(\"Resign Active\") }\n    .disposeWith(disposableBag)\n```\n\n### Bindings\n\nBindings in SignalKit are implemented again with protocol extensions. We extend the SignalType where the ObservationType (from the generic Observable protocol) is from a certain type and add method to bind the value to a UI control like \u003ccode\u003eUILabel\u003c/code\u003e.\nHere is an example of binding the String value from the signal to the text property of UILabel:\n\n```swift\nlet userName = Signal\u003cString\u003e()\nlet nameLabel = UILabel()\n\nuserName.bindTo(textIn: nameLabel)\n    .disposeWith(disposableBag)\n```\n\n## Signals\n\n#### Signal\n\u003ccode\u003eSignal\u003c/code\u003e is the primary object which you can use to send events and it is thread safe.\n\n#### SignalValue\n\u003ccode\u003eSignalValue\u003c/code\u003e is a signal that stores its last sent/current value. If we add a new observer to it it will send immediately its value to the newly added observer. If we change the value of the signal it will notify its observers for the change. \u003ccode\u003eSignalValue\u003c/code\u003e is also thread safe.\n\n```swift\nlet name = SignalValue(value: \"John\")\n\nname.next { print($0) }.disposeWith(bag) // prints \"John\"\n\nname.value = \"Jonathan\" // prints \"Jonathan\"\n```\n\n#### CollectionEvent\nWe can use a signal of type \u003ccode\u003eSignal\u0026lt;CollectionEvent\u0026gt;\u003c/code\u003e to send the changes that occur in our data source. Then we can bind the signal to \u003ccode\u003eUITableView\u003c/code\u003e or \u003ccode\u003eUICollectionView\u003c/code\u003e and the changes that we send will be reflected in the table/collection view:\n\n```swift\n// UsersListViewController\n...\nviewModel.usersChangeSignal.bindTo(tableView, rowAnimation: .Fade).disposeWith(bag)\n\n// UsersListViewModel\nlet usersChangeSignal = Signal\u003cCollectionEvent\u003e()\nvar users = [User]()\n...\n\nvar event = CollectionEvent()\n\nusers.insert(User(name: \"John\"), atIndex: 0)\nevent.itemInsertedAt(0, inSection: 0)\n\nusersChangeSignal.sendNext(event)\n```\n\n## Operations\n\nSignalKit comes with the following SignalType operations:\n![SignalKit Primary Protocols](https://raw.githubusercontent.com/yankodimitrov/SignalKit/SignalKit-4.0/Resources/signal-operations.png)\n\n## Extensions\n\nCurrently SignalKit comes with extensions for the the following \u003ccode\u003eUIKit\u003c/code\u003e components:\n![SignalKit Primary Protocols](https://raw.githubusercontent.com/yankodimitrov/SignalKit/SignalKit-4.0/Resources/uikit-extensions.png)\n\n### Keyboard\nYou can use the \u003ccode\u003eKeyboard\u003c/code\u003e structure to observe for keyboard events posted by the system. Then you will get back a structure of type \u003ccode\u003eKeyboardState\u003c/code\u003e which you can query for the keyboard end/start frame and other data that the system sends with the notification:\n\n```swift\nKeyboard.observe().willShow\n    .next { print($0.endFrame) }\n    .disposeWith(disposableBag)\n```\n\n## Installation\n\nSignalKit requires Swift 2.0 and Xcode 7\n\n#### Carthage\nAdd the following line to your [Cartfile](https://github.com/carthage/carthage)\n```swift\ngithub \"yankodimitrov/SignalKit\" \"master\"\n```\n\n#### CocoaPods\nAdd the following line to your [Podfile](https://guides.cocoapods.org/)\n```swift\npod “SignalKit”\n```\n\n##License\nSignalKit is released under the MIT license. See the LICENSE.txt file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyankodimitrov%2FSignalKit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyankodimitrov%2FSignalKit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyankodimitrov%2FSignalKit/lists"}