UberSignals 2.5.1

UberSignals 2.5.1

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最后一次发布2024年7月

Uber 维护。



signals

Build Status Coverage Status CocoaPods Compatible Carthage Compatible License Platform

signals是一个事件库,它允许您在不使用容易出错且笨拙的NSNotifications或代理的情况下实现 Observable 模式。

特性

  • 类型安全
  • 附加且忘记观察
  • 可配置的观察行为
  • 独立的回调队列
  • 全面的单元测试覆盖

安装

CocoaPods

要将signals集成到项目中,请将以下内容添加到您的Podfile

pod 'UberSignals', '~> 2.5'

Carthage

要使用Carthage将signals集成到项目中,请将以下内容添加到您的Cartfile

github "uber/signals-ios" ~> 2.5

简介

NSNotifications固有不安全性。在iOS 9之前,如果监听器在释放时未从通知中注销自己,触发通知会导致应用程序崩溃。如果您重构了与通知一起发送的数据,编译器不会警告您,但您的应用程序可能在运行时崩溃。

NSNotifications也不必要地范围广。任何人都可以监听它们,这在您的应用程序中隐式地将独立的组件耦合在一起。

使用NSNotifications,您在通知触发时注册一个要调用的选择器。这使得代码更难以阅读,因为它将注册通知位置和处理通知位置分离开来。

NSNotifications还需要大量样板代码来注册唯一的名称作为通知标识符。

signals解决了上述所有问题,并提供了一种内联的、类型安全和附加的解决方案来观察对象触发的事件。当不需要从代理返回数据时,它也是一个很好的替代品。

使用方法

通过在其头文件中声明Signals并在其初始化器中实现它来使一个类可观察

// Defines a new Signal type. This type is named "NetworkResult", and has two parameters 
// of type NSData and NSError. Note that the postfix "Signal" is automatically added to 
// the type name. Also note that only objects are allowed in Signal signatures.
CreateSignalType(NetworkResult, NSData *result, NSError *error)

@interface UBNetworkRequest

// We define two signals for our NetworkRequest class.
// - onNetworkResult will fire when a network result has been retreived.
// - onNetworkProgress will fire whenever download progresses.

// This uses the new signal type - NetworkResultSignal - that we've defined.
@property (nonatomic, readonly) UBSignal<NetworkResultSignal> *onNetworkResult;

// This makes use of a pre-defined signal type, FloatSignal.
@property (nonatomic, readonly) UBSignal<FloatSignal> *onNetworkProgress;

@end

@implementation UBNetworkRequest

- (instancetype)init {
  self = [super init];
  if (self) {
    // In the initializer the instance creates our signal
    _onNetworkResult = (UBSignal<NetworkResultSignal> *)
         [[UBSignal alloc] initWithProtocol:@protocol(NetworkResultSignal)];
    _onProgress = (UBSignal<FloatSignal> *)
         [[UBSignal alloc] initWithProtocol:@protocol(FloatSignal)];
   }
   return self;
}

- (void)receivedNetworkResult(NSData *data, NSError *error) 
{
  // Signal all listeners we're done loading
  _onNetworkProgress.fire(@(1.0))
  
  // Signal all listeners that we have data or an error
  _onNetworkResult.fire(myData, myError);
}

...

@end

任何可以访问NetworkResult实例的类都可以现在注册自己作为监听器,并在网络操作加载时收到通知

[networkRequest.onNetworkResult addObserver:self 
            callback:^(typeof(self) self, NSData *data, NSError *error) {
    // Do something with the result. The self passed into the block is 
    // weakified by Signals to guard against retain cycles.
}];

要取消单个观察器,请对返回的UBSignalObserver调用cancel

UBSignalObserver *observer = [networkRequest.onNetworkResult addObserver:self 
        callback:^(typeof(self) self, NSData *data, NSError *error) {
    ...
}];
...
[observer cancel];

高级用法

您可以将观察器配置为在观察信号触发一次后取消自身

[networkRequest.onNetworkResult addObserver:self 
            callback:^(typeof(self) self, NSData *data, NSError *error) {
    ...
}].cancelsAfterNextFire = YES;

默认情况下,回调在信号触发的相同的NSOperationQueue上被调用。要使其在不同的队列上触发,只需更改返回UBSignalObserver的操作队列参数。

[networkRequest.onNetworkResult addObserver:self 
            callback:^(typeof(self) self, NSData *data, NSError *error) {
    ....
}].operationQueue = NSOperationQueue.mainQueue;

signals会记住上次触发时携带的数据,您可以强制观察器触发

[[networkRequest.onNetworkResult addObserver:self 
            callback:^(typeof(self) self, NSData *data, NSError *error) {
    ....
}] firePreviousData];

Swift支持

上述描述的基于协议的方法是定义新信号类型的最简单方法。然而,不幸的是,这些类型无法从Swift代码中访问。为了让Swift正确理解信号类型,您必须为每种信号类型创建具体子类。Signals提供了两个宏来完成此操作:使用CreateSignalInterface来创建子类的接口,以及使用CreateSignalImplementation来创建实现。在声明类中的信号时,您将使用这些具体子类。

// Defines a new Signal interface, a sub-class of UBSignal with the given
// name and parameters
CreateSignalInterface(UBNetworkResultSignal, NSData *result, NSError *error)

@interface UBNetworkRequest

// We declare the signal with the concrete type
@property (nonatomic, readonly) UBNetworkResultSignal *onNetworkResult;

@end


// In your .m-file you also create the implementation for the sub-class

CreateSignalImplementation(UBNetworkResultSignal, NSData *result, NSError *error)

@implementation UBNetworkRequest

- (instancetype)init {
  self = [super init];
  if (self) {
    // You initialize it without a protocol
    _onNetworkResult = [[UBNetworkResultSignal alloc] init];
   }
   return self;
}

- (void)receivedNetworkResult(NSData *data, NSError *error) 
{
  // And use it as you normally would
  _onNetworkResult.fire(myData, myError);
}

最大观察者数量

信号默认最大观察者数量为100,并且将NSAssert您不会向其中添加更多观察者。这是为了让您意识到可能无意中过度订阅信号的情况(例如,由于内存泄漏或重新注册观察者)。

如果您有正当理由提高此限制,可以设置信号的maxObservers属性。

_onNetworkResult = (UBSignal<NetworkResultSignal> *)
      [[UBSignal alloc] initWithProtocol:@protocol(NetworkResultSignal)];
      
_onNetworkResult.maxObservers = 500;

信号命名

使用CreateSignalType宏创建的每个信号类型都会创建一个新的协议,以便编译器可以强制执行类型安全。这意味着您为信号类型选择的名称需要与您的项目唯一。

通常,信号会触发没有任何参数或一个基本ObjC类型的参数。因此,Signals预先定义了一组您可以用作信号类型的类型。

EmptySignal, fires no parameters
IntegerSignal, fires a NSNumber
FloatSignal, fires a NSNumber
DoubleSignal, fires a NSNumber
BooleanSignal, fires a NSNumber
StringSignal, fires a NSString
ArraySignal, fires a NSArray
MutableArraySignal, fires a NSMutableArray
DictionarySignal, fires a NSDictionary
MutableDictionarySignal, fires a NSMutableDictionary

贡献

我们乐于看到您为我们开源项目贡献力量。在我们接受您的贡献之前,我们恳请您签署我们的Uber贡献者许可协议

  • 如果您发现了一个错误,请打开一个issue或通过pull request提交修复。
  • 如果您有功能请求,请打开一个issue或通过pull request提交实现。
  • 如果您想做出贡献,请提交一个pull request。

许可证

Signals在MIT许可下发布。有关更多信息,请参阅LICENSE文件。