Skip to content

MDListener

剑川道长 edited this page Nov 1, 2018 · 15 revisions

MDListener是一个高扩展性的、易用的监听者模式的实现

使用方法示例 (全部代码参见Demo中的单元测试用例TMDListener)

Demo代码中的角色

TMDListener: 测试用例(监听者)

TListenerLoginModule: 登录模块(被监听者)

步骤

1. 登录模块定义消息协议:

@protocol TMDListenerLoginNotification <NSObject>

- (void)didLogin;

@end

登录模块定义协议,监听者遵守协议。这样登录模块就可以通过MDListener来触发监听者的协议方法了。

2. 登录模块提供listeners属性

@property (nonatomic, strong) MDListener <id <TMDListenerLoginNotification>> *listeners;

其中,listeners的类型为一个泛型,它只接受其指定类型的实例作为监听者。在Demo中,也就是实现了TMDListenerLoginNotification协议的实例对象。这在后续步骤中也会提及。

3. 登录模块在适当的时机触发消息发送

在Demo中即为+ (void)login方法

+ (void)login {
    //do login
    [[self sharedInstance].listeners performAction:^(id<TMDListenerLoginNotification>  _Nonnull listener) {
        [listener didLogin];
    }];
}

4. 监听者申明自己遵守TMDListenerLoginNotification协议

@interface TMDListener : XCTestCase <TMDListenerLoginNotification>

5. 监听者在适当的时机,将自己加入到listeners中

- (void)setUp {
    [[TListenerNetworkingModule sharedInstance].listeners addListener:self];
    [super setUp];
}

这里注意,由于登录模块在声明listeners属性的时候,通过泛型定义了其只接受遵循TMDListenerLoginNotification协议的id类型,因此如果步骤4中没有声明自己实现该协议,这里的addListener的时候就会报warning。这里利用了编译器来减少bug的产生。

6. 监听者实现协议接受消息

- (void)didLogin {
    NSLog(@"didLogin");
    self.hasLogin = YES;
}

7. 测试用例

- (void)testListener {
    [TListenerLoginModule login];
    XCTAssertTrue(self.hasLogin);
}

MDListener的优势

扩展性

被监听者指定监听者必须实现某些方法:

MDListener帮助被监听者管理所有的监听者,而其声明的监听者类型是一个泛型。因此,当被监听者声明MDListener对象的时候,可以定义监听者类型。也就是说,被监听者决定了监听者类型,这通常是id类型带一个协议,而通常该协议由被监听者在头文件中声明,换句话说,被监听者通过这种方式,决定监听者必须实现哪些方法(或者可选实现)。

被监听者指定监听者为某些特殊类型:

当然,被监听者也可以定义该泛型为其他类型,比如在特定的情况下,被监听者可以定义监听者的类型为UIViewController等其他类型,或者开发者在项目中自定义的其他类型,由此来完成特定的任务。

易用性

1.无需removeListener

MDListener帮助被监听者管理所有的监听者,并自动在监听者被析构的时候移除。因此,监听者无需在dealloc方法中调用类似于removeListener的方法。

2.相比NSNotificationCenter

和NSNotificationCenter模式相比,MDListener可以通过泛型加协议的方式,规定监听必须实现一些方法。开发者在写监听者代码的时候,如果忘记实现这些方法,则编译器会报warning。另外,参数传递通过函数形参的方式传递,而不是NSDictionary。开发者在写监听者代码时,不会因为不了解NSDictionary的数据结构,以及这些数据所对应的业务含义,而产生困惑,从而产生不必要的开发成本。

3.相比KVO

和KVO相比,MDListener不需要依赖属性即可完成监听者模式。当然,KVO也有其优势,在KVO模式下,被监听者无需为实现监听者模式,提供任何额外的代码。