协议
概念
协议是方法列表。在实际应用中通过协议来规定代理双方的行为。
声明类的协议
协议就是定义公共接口的地方,只要遵守协议,就等于在头文件中定义了这些方法,只要实现就行了。
所以,你可以定义一个协议,然后定义一个类遵循这个协议,在这个类的.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];
之所以有这样的设计,是因为要将共同的行为抽象出来:不同的类有不同的作用和特征,这也是面向对象的特点,但是即使千差万别,还是会有某些相似点的,这些相似的地方就可以抽象出来做成协议。
其关系如下图:
那么我们就可以将各个类的协议统一放在一个协议类里(例如把不同种类的菜都放在做菜协议里),不同的类遵循不同的协议(不同的厨师完成不同的具体菜品),这样在实现功能时我们只需在协议里寻找对应方法(具体菜品),然后找到遵循此协议的类(菜品对应的厨师),就可以实现具体功能,使代码逻辑更加清晰。
在一个完全组件化的项目中,关系如下图。
定义一个基础协议,协议中包含很多相关方法。例如菜单协议,内包含很多具体菜名。然后有若干的类(厨师),遵循该协议,实现部分对应方法。使用字典的方式进行组件化注册。在公共部分,根据协议找到实现的Class。并使用class实例执行方法。
组件中只需要开放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];
协议用于做封装
比如现在有一个MeetingUser
的类,其中的有很多属性方法,只有部分属性及部分方法暴露出去。
//interface.h中
- (void)getUser:(id<CustomProtocol>)user;
定义CustomProtocol协议,声明准备暴露出去的属性(属性的get方法)及方法。
@protocol CustomProtocol
- (NSString *)getPropertyA;
- (NSString *)getPropertyB;
- (void)methodA;
原有的MeetingUser
遵循该协议,实现其定义的方法(属性等原方法不变)。
在getUser
中直接返回MeetingUser
对象即可。对外来说只是一个id类型遵循CustomProtocol
的对象。可以使用该对象直接执行协议中方法。
以这样的方式实现封装。
代理
概念
为其他对象提供一种代理以控制对这个对象的访问。
代理模式分为三部分:委托方,代理方,协议。
委托方:tableview
协议:UITableviewdelegate,UITableviewDatasource
代理方:遵循协议的controller。
可以使用tableview.delegate=self来使本控制器来做代理方。
也可以新建一个类,例如tableviewDelegate类A。实例化该类,tableview.delegate = A.init。使A的实例作为代理方。在A类中实现协议中的方法。
id<UItableviewDelegate> delegate
一个任意类型可以遵循该协议的具体对象。该实例可以作为变量,可以作为参数传递。该实例必然可以执行协议中的方法。
总结
tableview 定义了一个协议 tableviewdelegate 和tableviewdatasource。tableview作为委托方,制定了一个方法列表,找人帮它实现。viewcontroller使用了tableview,那么必须要为tableview指定一个代理方,可以是自己,也可以再找一个。