声明类的协议
协议就是定义公共接口的地方,只要遵守协议,就等于在头文件中定义了这些方法,只要实现就行了。
所以,你可以定义一个协议,然后定义一个类遵循这个协议,在这个类的.m文件里实现这个协议中的方法。这样不需要在.h中声明,也可以在其他类中调用该类对应协议中的方法。如下:
- 定义协议
#import <Foundation/Foundation.h>
@class HWWashDevice;
@protocol HWWashDeviceParserProtocol <NSObject>
@required
- (void)hw_ParseWashDevice:(HWWashDevice *)device;
@end
- 对应方法中实现
@implementation HWDeviceParser
+ (instancetype)defaultParser
{
HWDeviceParser *parser = [[HWDeviceParser alloc] init];
return parser;
}
- (void)hw_ParseWashDevice:(HWWashDevice *)device
{
//解析洗衣机属性
...
...
...
}
- 对该方法的调用
@interface HWWashDevice ()
@property (strong, nonatomic) id<HWWashDeviceParserProtocol> attributeparser;
@end
- (void)setUp
{
self.attributeparser = [HWDeviceParser defaultParser];
...
}
/**
* 设备属性状态变化
*
* @param device 设备对象
* @param attributes 属性发生变化的集合
*/
- (void)device:(uSDKDevice *)device didUpdateVlaueForAttributes:(NSArray<uSDKDeviceAttribute *> *)attributes
{
NSLog(@"todo:%@", attributes);
[super device:device didUpdateVlaueForAttributes:attributes];
之所以有这样的设计,是因为要将共同的行为抽象出来:不同的类有不同的作用和特征,这也是面向对象的特点,但是即使千差万别,还是会有某些相似点的,这些相似的地方就可以抽象出来做成协议。
其关系如下图:
![](https://img.haomeiwen.com/i5687317/c413d3bad0a09f2f.jpeg)
那么我们就可以将各个类的协议统一放在一个协议类里(例如把不同种类的菜都放在做菜协议里),不同的类遵循不同的协议(不同的厨师完成不同的具体菜品),这样在实现功能时我们只需在协议里寻找对应方法(具体菜品),然后找到遵循此协议的类(菜品对应的厨师),就可以实现具体功能,使代码逻辑更加清晰。
在一个完全组件化的项目中,关系如下图。
![](https://img.haomeiwen.com/i5687317/843f4480b2ef7c7a.jpeg)
组件中只需要开放protocol与service即可,其他的所有内容在内部实现,不做开放。
而公共部分只需要找到需要的protocol,即可实现对应方法。
实例
-
协议部分
MSViewModelServicesImpl
遵循MSViewModelServices
遵循MSNavigationProtocol
定义方法若干:/// Pushes the corresponding view controller. /// /// Uses a horizontal slide transition. /// Has no effect if the corresponding view controller is already in the stack. /// /// viewModel - the view model /// animated - use animation or not - (void)pushViewModel:(MSViewModel *)viewModel animated:(BOOL)animated; /// Pops the top view controller in the stack. /// /// animated - use animation or not - (void)popViewModelAnimated:(BOOL)animated; /// Pops until there's only a single view controller left on the stack. /// /// animated - use animation or not - (void)popToRootViewModelAnimated:(BOOL)animated; /// Present the corresponding view controller. /// /// viewModel - the view model /// animated - use animation or not /// completion - the completion handler - (void)presentViewModel:(MSViewModel *)viewModel animated:(BOOL)animated completion:(VoidBlock)completion; /// Dismiss the presented view controller. /// /// animated - use animation or not /// completion - the completion handler - (void)dismissViewModelAnimated:(BOOL)animated completion:(VoidBlock)completion; /// Reset the corresponding view controller as the root view controller of the application's window. /// /// viewModel - the view model - (void)resetRootViewModel:(MSViewModel *)viewModel;
-
实现部分:
传统方式遵循该协议,并实现协议对应方法。
RAC 实现方式如下:// 不需要遵循该协议。而是创建时传入该协议使之持有。 - (instancetype)initWithServices:(id<MSViewModelServices>)services;
初始化时注册代理实现方法。
- (void)registerNavigationHooks { @weakify(self) // 使用RAC监测方法调用,当方法调用时运行block内部代码,实际上就是协议方法的具体实现。 [[(NSObject *)self.services rac_signalForSelector:@selector(pushViewModel:animated:)] subscribeNext:^(RACTuple *tuple) { @strongify(self) MSViewController *topViewController = (MSViewController *)[self.navigationControllers.lastObject topViewController]; if (topViewController.tabBarController) { topViewController.snapshot = [topViewController.tabBarController.view snapshotViewAfterScreenUpdates:NO]; } else { topViewController.snapshot = [[self.navigationControllers.lastObject view] snapshotViewAfterScreenUpdates:NO]; } UIViewController *viewController = (UIViewController *)[MSRouter.sharedInstance viewControllerForViewModel:tuple.first]; [self.navigationControllers.lastObject pushViewController:viewController animated:[tuple.second boolValue]]; }]; }
-
调用
最后 viewModel 中再持有一份这个协议。
利用如下方式调用:[self.viewModel.services pushViewModel:model animated:YES];
网友评论