{"id":1104,"url":"https://github.com/uber/signals-ios","last_synced_at":"2025-06-11T17:39:41.269Z","repository":{"id":33946226,"uuid":"37672183","full_name":"uber/signals-ios","owner":"uber","description":"Typeful eventing","archived":false,"fork":false,"pushed_at":"2019-01-04T23:17:33.000Z","size":97,"stargazers_count":527,"open_issues_count":2,"forks_count":55,"subscribers_count":2657,"default_branch":"master","last_synced_at":"2024-11-14T14:08:35.773Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uber.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}},"created_at":"2015-06-18T16:48:58.000Z","updated_at":"2024-11-02T18:06:53.000Z","dependencies_parsed_at":"2022-07-13T18:20:39.429Z","dependency_job_id":null,"html_url":"https://github.com/uber/signals-ios","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber%2Fsignals-ios","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber%2Fsignals-ios/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber%2Fsignals-ios/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber%2Fsignals-ios/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uber","download_url":"https://codeload.github.com/uber/signals-ios/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228179191,"owners_count":17881139,"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-01-05T20:15:38.990Z","updated_at":"2024-12-04T19:32:53.623Z","avatar_url":"https://github.com/uber.png","language":"Objective-C","funding_links":[],"categories":["EventBus","Objective-C","HarmonyOS"],"sub_categories":["Getting Started","Other free courses","Linter","Windows Manager"],"readme":"# Signals\n\n[![Build Status](https://travis-ci.org/uber/signals-ios.svg?branch=master)](https://travis-ci.org/uber/signals-ios)\n[![Coverage Status](https://coveralls.io/repos/uber/signals-ios/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/uber/signals-ios?branch=master)\n[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/UberSignals.svg)](https://cocoapods.org/pods/UberSignals)\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n![License](https://img.shields.io/cocoapods/l/Signals.svg?style=flat\u0026color=gray)\n![Platform](https://img.shields.io/cocoapods/p/UberSignals.svg?style=flat)\n\nSignals is an eventing library that enables you to implement the Observable pattern without using error prone and clumsy NSNotifications or delegates.\n\n\n## Features\n\n- [x] Type-safety\n- [x] Attach-and-forget observation\n- [X] Configurable observation behaviour\n- [x] Separate callback queues\n- [x] Comprehensive Unit Test Coverage\n\n## Installation\n#### CocoaPods\n\nTo integrate Signals into your project add the following to your `Podfile`:\n\n```ruby\npod 'UberSignals', '~\u003e 2.5'\n```\n\n#### Carthage\n\nTo integrate Signals into your project using Carthage add the following to your `Cartfile`:\n\n```ruby\ngithub \"uber/signals-ios\" ~\u003e 2.5\n```\n\n## Introduction\n\nNSNotifications are inherently error prone. Prior to iOS 9, if a listener doesn’t de-register itself from a notification when it’s deallocated, firing the notification will crash the application. If you refactor the data you send with a notification, the compiler won't warn you but your app might crash at runtime.\n\nNSNotifications are also unnecessarily broad. Anyone can listen in on them which couples separate components in your application implicitly together.\n\nWith NSNotifications you register a selector to be invoked when a notification fires. This makes code less readable by separating where you register for notifications and where you handle notifications.\n\nNSNotifications also require a lot of boilerplate code to register unique names to use as notification identifiers.\n\nSignals solves all of the above problems and provides an inline, type-safe and attach-and-forget way to observe events being fired by objects. It is also a great replacement for delegates when there is no need to return data from the delegates.\n\n# Usage\n\nMake a class observable by declaring a Signals in its header and implementing it in its initializer:\n\n```objective-c\n\n// Defines a new Signal type. This type is named \"NetworkResult\", and has two parameters \n// of type NSData and NSError. Note that the postfix \"Signal\" is automatically added to \n// the type name. Also note that only objects are allowed in Signal signatures.\nCreateSignalType(NetworkResult, NSData *result, NSError *error)\n\n@interface UBNetworkRequest\n\n// We define two signals for our NetworkRequest class.\n// - onNetworkResult will fire when a network result has been retreived.\n// - onNetworkProgress will fire whenever download progresses.\n\n// This uses the new signal type - NetworkResultSignal - that we've defined.\n@property (nonatomic, readonly) UBSignal\u003cNetworkResultSignal\u003e *onNetworkResult;\n\n// This makes use of a pre-defined signal type, FloatSignal.\n@property (nonatomic, readonly) UBSignal\u003cFloatSignal\u003e *onNetworkProgress;\n\n@end\n\n@implementation UBNetworkRequest\n\n- (instancetype)init {\n  self = [super init];\n  if (self) {\n    // In the initializer the instance creates our signal\n    _onNetworkResult = (UBSignal\u003cNetworkResultSignal\u003e *)\n         [[UBSignal alloc] initWithProtocol:@protocol(NetworkResultSignal)];\n    _onProgress = (UBSignal\u003cFloatSignal\u003e *)\n         [[UBSignal alloc] initWithProtocol:@protocol(FloatSignal)];\n   }\n   return self;\n}\n\n- (void)receivedNetworkResult(NSData *data, NSError *error) \n{\n  // Signal all listeners we're done loading\n  _onNetworkProgress.fire(@(1.0))\n  \n  // Signal all listeners that we have data or an error\n  _onNetworkResult.fire(myData, myError);\n}\n\n...\n\n@end\n```\n\nAny class who has access to the NetworkResult instance, can now register itself as a listener and get notified whenever the network operation has loaded:\n\n```objective-c\n[networkRequest.onNetworkResult addObserver:self \n            callback:^(typeof(self) self, NSData *data, NSError *error) {\n    // Do something with the result. The self passed into the block is \n    // weakified by Signals to guard against retain cycles.\n}];\n```\n\nTo cancel a single observer, call cancel on the returned UBSignalObserver:\n\n```objective-c\nUBSignalObserver *observer = [networkRequest.onNetworkResult addObserver:self \n        callback:^(typeof(self) self, NSData *data, NSError *error) {\n    ...\n}];\n...\n[observer cancel];\n```\n\n### Advanced usage\n\nYou can configure the observer to cancel itself after it has observed a signal firing once:\n\n```objective-c\n[networkRequest.onNetworkResult addObserver:self \n            callback:^(typeof(self) self, NSData *data, NSError *error) {\n    ...\n}].cancelsAfterNextFire = YES;\n```\n\nThe callback is by default called on the same NSOperationQueue than the signal fires on. To have it fire on a different queue, simply change the operationQueue parameter of the returned UBSignalObserver.\n\n```objective-c\n[networkRequest.onNetworkResult addObserver:self \n            callback:^(typeof(self) self, NSData *data, NSError *error) {\n    ....\n}].operationQueue = NSOperationQueue.mainQueue;\n```\n\nSignals remember with what data they were last fired with and you can force an observer to fire\n\n```objective-c\n[[networkRequest.onNetworkResult addObserver:self \n            callback:^(typeof(self) self, NSData *data, NSError *error) {\n    ....\n}] firePreviousData];\n```\n\n### Swift support\n\nThe protocol-based approach described above is the easiest way to define new Signal types. However, these are unfortunately not accessible from Swift code. In order for Swift to understand the type of your signals correctly, you have to create concrete sub-classes for each signal type. Signals provides two macros to do this: `CreateSignalInterface` to create the interface for your sub-class and `CreateSignalImplementation` to create the implementation. You then use the concrete sub-classes when you declare the signals for your class:\n\n```objective-c\n\n// Defines a new Signal interface, a sub-class of UBSignal with the given\n// name and parameters\nCreateSignalInterface(UBNetworkResultSignal, NSData *result, NSError *error)\n\n@interface UBNetworkRequest\n\n// We declare the signal with the concrete type\n@property (nonatomic, readonly) UBNetworkResultSignal *onNetworkResult;\n\n@end\n\n\n// In your .m-file you also create the implementation for the sub-class\n\nCreateSignalImplementation(UBNetworkResultSignal, NSData *result, NSError *error)\n\n@implementation UBNetworkRequest\n\n- (instancetype)init {\n  self = [super init];\n  if (self) {\n    // You initialize it without a protocol\n    _onNetworkResult = [[UBNetworkResultSignal alloc] init];\n   }\n   return self;\n}\n\n- (void)receivedNetworkResult(NSData *data, NSError *error) \n{\n  // And use it as you normally would\n  _onNetworkResult.fire(myData, myError);\n}\n```\n\n\n\n## Max observers\n\nSignals have a default maximum observer count of 100 and signals will NSAssert that you don't add more observers to them. This is to make you aware of situations where you are unknowingly oversubscribing to a signal (e.g. beause of memory leaks or re-registering an observer). \n\nIf you have a legitimate case of increasing this limit, you can set the `maxObservers` property of a signal.\n\n```objective-c\n_onNetworkResult = (UBSignal\u003cNetworkResultSignal\u003e *)\n      [[UBSignal alloc] initWithProtocol:@protocol(NetworkResultSignal)];\n      \n_onNetworkResult.maxObservers = 500;\n```\n\n\n## Signal naming\n\nEach signal type created with the CreateSignalType macro creates a new protocol so that the compiler can enforce type safety. This means that the name you choose for your signal types need to be unique to your project. \n\nFrequently, a signal will fire no parameters or one parameter of the basic ObjC types. Signals therefore predefines a set of signal types that you can use:\n\n```objective-c\nEmptySignal, fires no parameters\nIntegerSignal, fires a NSNumber\nFloatSignal, fires a NSNumber\nDoubleSignal, fires a NSNumber\nBooleanSignal, fires a NSNumber\nStringSignal, fires a NSString\nArraySignal, fires a NSArray\nMutableArraySignal, fires a NSMutableArray\nDictionarySignal, fires a NSDictionary\nMutableDictionarySignal, fires a NSMutableDictionary\n```\n\n## Contributions\n\nWe'd love for you to contribute to our open source projects. Before we can accept your contributions, we kindly ask you to sign our [Uber Contributor License Agreement](https://docs.google.com/a/uber.com/forms/d/1pAwS_-dA1KhPlfxzYLBqK6rsSWwRwH95OCCZrcsY5rk/viewform).\n\n- If you **find a bug**, open an issue or submit a fix via a pull request.\n- If you **have a feature request**, open an issue or submit an implementation via a pull request\n- If you **want to contribute**, submit a pull request.\n\n## License\n\nSignals is released under a MIT license. See the LICENSE file for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuber%2Fsignals-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuber%2Fsignals-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuber%2Fsignals-ios/lists"}