RZDataBinding 2.1.1

RZDataBinding 2.1.1

测试已测试
Lang语言 Obj-CObjective C
许可 NOASSERTION
发布上次发布2018年10月

Rob VisentinRightpoint CIRaiz Labs维护。



  • Rob Visentin

RZDataBinding

Version CircleCI License Platform

RZDataBinding

概述

RZDataBinding是一个框架,旨在帮助保持iOS或OS X应用程序中的数据完整。它是使用标准的键值观察(KVO)框架构建的,但更加安全并提供额外的功能。与KVO类似,RZDataBinding通过为对象状态变化建立直接回调来帮助避免无休止的代理链。

安装

使用CocoaPods(推荐)安装,在Podfile中添加以下行

pod "RZDataBinding"

或者,下载仓库并将RZDataBinding目录的内容添加到您的项目中。

示例项目

在示例目录中提供了一个示例项目。您可以通过以下方式快速查看:

pod try RZDataBinding

或者从GitHub下载zip文件并手动运行。

RZDataBinding

此演示展示了RZDataBinding的基本用法,但绝非规范或最高级别的用例。

使用方法

为对象的键路径变化注册回调

// Register a selector to be called on a given target whenever keyPath changes on the receiver.
// Action must take either zero or exactly one parameter, an NSDictionary. 
// If the method has a parameter, the dictionary will contain values for the appropriate 
// RZDBChangeKeys. If keys are absent, they can be assumed to be nil. Values will not be NSNull.
- (void)rz_addTarget:(id)target
              action:(SEL)action
    forKeyPathChange:(NSString *)keyPath;

通过直接或通过函数将两个对象的值绑定在一起

// Binds the value of a given key of the receiver to the value of a key path of another object. 
// When the key path of the object changes, the bound key of the receiver is also changed.
- (void)rz_bindKey:(NSString *)key
         toKeyPath:(NSString *)foreignKeyPath
          ofObject:(id)object;

// Same as the above method, but the binding function is first applied 
// to the changed value before setting the value of the bound key.
// If nil, the identity function is assumed, making it identical to regular rz_bindKey.
- (void)rz_bindKey:(NSString *)key 
         toKeyPath:(NSString *)foreignKeyPath 
          ofObject:(id)object
      withFunction:(RZDBKeyBindingFunction)bindingFunction;

可以使用相应的删除方法删除目标和解除键的绑定,但与标准KVO不同,您不必这样做。RZDataBinding将在对象释放前自动清理观察者。

为什么不使用平凡的KVO呢?

考虑以下代码,当用户对象的名称更改时调用nameChanged,当用户的首选项更改时重新加载集合视图

使用KVO

static void* const MyKVOContext = (void *)&MyKVOContext;

- (void)setupKVO
{
    [self.user addObserver:self
                forKeyPath:@"name"
                   options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
                   context:MyKVOContext]; 
                  
    [self.user addObserver:self
                forKeyPath:@"preferences"
                   options:kNilOptions
                   context:MyKVOContext];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object change:(NSDictionary *)change
                       context:(void *)context
{
  if ( context == MyKVOContext ) {
        if ( [object isEqual:self.user] ) {
            if ( [keyPath isEqualToString:@"name"] ) {
                [self nameChanged:change];
            }
            else if ( [keyPath isEqualToString:@"preferences"] ) {
                [self.collectionView reloadData];
            }
        }
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)dealloc
{
    [self.user removeObserver:self forKeyPath:@"name" context:MyKVOContext];
    [self.user removeObserver:self forKeyPath:@"preferences" context:MyKVOContext];
}

使用RZDataBinding

- (void)setupKVO
{
    [self.user rz_addTarget:self 
                     action:@selector(nameChanged:) 
           forKeyPathChange:@"name"];
    
    [self.user rz_addTarget:self.collectionView 
                     action:@selector(reloadData) 
           forKeyPathChange:@"preferences"];
}

除了代码量明显减少外,RZDataBinding实现还展示了其他一些优点

  1. 无需管理不同的KVO上下文并检查哪些对象/键路径发生了变化
  2. 不需要实现实例方法,这意味着任何对象都可以添加为目标
  3. 不需要在释放前进行拆除(标准的KVO如果在失败时执行此操作会崩溃)

安全键路径

RZDataBinding还提供了几个便利宏,用于创建类型安全的键路径。在DEBUG模式下运行时,无效的键路径将引发编译器错误

// Creates the keypath @"text", ensuring it exists on objects of type UILabel
RZDB_KP(UILabel, text);

// Creates @"layer.cornerRadius", ensuring the keypath exists on myView
RZDB_KP_OBJ(myView, layer.cornerRadius);

// Creates @"session.user.name", ensuring the keypath exists on self
RZDB_KP_SELF(session.user.name);

您应该始终使用这些宏而不是 literal 字符串,因为这些宏提供了额外的类型检查。请注意,在生产环境中,这些宏会简化为 literal 字符串生成,以避免任何额外的开销。

回调合并(高级)

RZDataBinding 也可以提供一种合并机制,用于微调那些接收或发送许多KVO通知的应用程序区域,这可能影响性能。例如,一个复杂的视图可能在多个属性的其中一个变化时触发昂贵的布局操作。或者,有些工作可能需要多次更改属性,直到它们达到最终值。在这些情况下,将工作块视为“原子”事件可能会有所帮助。也就是说,支持的回调应该合并并集中一次,当工作完成后发送。

RZDBCoalesce 提供了一个块接口

[RZDBCoalesce coalesceBlock:^{
        // Callbacks within this block are coalesced,
        // and sent only once, after the block completes
}];

默认情况下,回调不会合并,即使在 RZDBCoalesce 事件内部。可以使用 rz_addTarget:action: 方法通过指定合并代理作为回调目标来选择支持合并。

[object rz_addTarget:[self rz_coalesceProxy] 
              action:@selector(expensiveCallback) 
    forKeyPathChange:RZDB_KP_OBJ(object, key.path)];

在这个示例中,目标应该是 self,但是如果正在进行合并事件,这些消息将合并并延迟,直到事件完成。请注意,只有 rz_addTarget:action: 回调可以支持合并;使用 rz_bindKey: 方法建立的绑定永远不会合并。

作者

Rob Visentin, [email protected]

许可证

RZDataBinding 在 MIT 许可下可用。更多信息请参阅 LICENSE 文件。