Facebook Flux启发的事件分发器架构,针对Objective-C调整并附加了一些魔法
在开始之前,你可能需要阅读并理解Facebook围绕此库创建的默认Flux分发器实现,并理解其中的差异。请参见Flux文档
首先,让我们来看看这个库与默认Flux实现之间的一些主要区别,其中许多是由JavaScript和Objective-C之间的差异所引发的。
相反,分发器基于注册存储类本身。
[[JBDispatcher sharedInstance] registerStore:[SomeStore class]]
一旦一个存储与分发器注册(在此例中为分发器单例sharedInstance),它将被分发器自动实例化,并将在整个JBDispatcher
实例寿命期内存在。在存储与分发器注册后,可以随时通过调用分发器的store:
函数来检索它。
[[JBDispatcher sharedInstance] store:[SomeStore class]]
这种方式下,技术上可以拥有多个分发器,但更重要的是,您无需担心在所有JBStore
子类中实现通常的Objective-C Singleton dispatch_once
sharedInstance代码。
这允许做两件事,首先,避免在存储中创建庞大的switch语句。相反,您可以直接将您的动作映射到基于JBStore
协议的JBStore
子类实现的处理器方法。您需要做的就是实现您JBStore
子类中的actionHandlerNamesByActionEventNames
函数。
如果您过去使用过Mantle Model框架,您可能会觉得这很熟悉。
例如
@implementation CurrentUserStore // JBStore subclass
+ (NSDictionary *)actionHandlerNamesByActionEventNames {
return @{
@"CurrentUserRefreshedAction": @"onCurrentUserRefreshedAction"
};
}
- (void)onCurrentUserRefreshedAction:(JBAction<UserModel *> *)action {
// do something with action.payload, in this case the action payload is casted to your UserModel class automatically using generics.
self.currentUserModel = action.payload;
}
@end
稍后,当将'CurrentUserRefreshedAction'操作分派到分派器时,你的动作处理程序将自动由分派器调用。
...
[[JBDispatcher sharedInstance] dispatch:[JBAction actionWithEventName:@"CurrentUserRefreshedAction" payload:userModel]]];
...
// - (void)onCurrentUserRefreshedAction:(JBAction<UserModel *> *)action is called
JBAction
这是一个包含一个公共NSString *eventName
属性,一个泛型id<PayloadType> payload
属性(您可以将任何类型的对象传递和转换为它),以及一个NSError *error
属性的简单类。
与默认的随时可用的Flux动作对象相比,这有点个人观点,但它允许做三件事
首先,这允许您在动作处理程序方法中直接预转换您的JBAction
有效负载类型,正如以前展示的那样,这样您就不必在动作处理程序方法实现中转换您的JBAction
有效负载类型。
其次,它允许您在代码中间接指定结构返回的特定动作的有效负载类型,这样您以后就不必查看动作创建器实现来记住特定的动作有效负载类型。
第三,JBAction
类中可用的错误参数可以避免您需要根据给定动作的成功或失败创建多个相同动作的版本。
例如,您可能在许多Flux代码中看到过类似这样的多人实现相同动作的多个版本
'CurrentUserRefreshedAction', 'CurrentUserRefreshedActionSuccess' and 'CurrentUserRefreshedActionFailure'
由于每个JBAction
都有一个可选的错误属性,您可以在JBAction
错误属性不为空时简单地假设可能发生了错误
- (void)onCurrentUserRefreshedAction:(JBAction<UserModel *> *)action {
if (action.error) {
// React to the action failure, for example:
self.currentUserModel = nil;
}
[self emitChangeWithError:error];
}
这样,您不必记住与您的动作相关的许多讨厌的常量字符串,并且也限制了您必须实现的动作处理程序方法数量。
在一个普通的应用程序中,您应该首先将所有您的存储子类注册到您的分派器
[SomeDispatcher registerStore:[CurrentUserStore class]];
[SomeDispatcher registerStore:[CurrentUserMessagesStore class]];
...
之后,您的视图控制器/视图模型可以使用一个块绑定到您的JBStore
变更事件
@implementation SomeViewController
- (instancetype)init {
...
// Retrieve the registered store
CurrentUserStore *userStore = [SomeDispatcher store:[CurrentUserStore class]];
// Bind the viewController to this store change events with a callback block
__weak __typeof(self) weakself = self;
[userStore registerObject:self forChangeEvents:^(CurrentUserStore *store, NSError *error) {
// Update some views, react to an error, etc
}];
...
}
注意,我们将视图控制器实例本身及其回调绑定到存储上。这允许您不必担心在视图控制器中移除对存储变更事件回调的注销,就像您通常在为NSNotification
事件注册视图控制器时那样。
之后,您可以简单地创建JBActions
,将它们分派到您的分派器,并如开始部分所述在您的存储中处理它们。
我还未涉及到动作创建者,这可能是您是否想要实现的事情,但如果您计划使用此模式,创建所有动作创建者的JBAction
类别是一个好的方法以保持一致性。
extern NSString * const CurrentUserRefreshedAction;
@interface JBAction (UserActionCreator)
+ (JBAction<UserModel *>)currentUserRefreshedAction:(UserModel *)userModel;
@end
JBFlux工作空间提供了一个示例项目,您可以从该工作空间本身运行示例。
请确保在 JBFlux 根目录中运行一个pod install
,因为示例项目有一些外部依赖项。
JBFlux 要求 iOS 7.0+ 或 Mac OS X 10.7+ 或 watchOS 2.0。
需要 ARC
JBFlux 是以 MIT 许可证授权的