協(xié)議與代理

協(xié)議

概念

協(xié)議是方法列表。在實際應(yīng)用中通過協(xié)議來規(guī)定代理雙方的行為。

聲明類的協(xié)議

協(xié)議就是定義公共接口的地方,只要遵守協(xié)議,就等于在頭文件中定義了這些方法,只要實現(xiàn)就行了。
所以,你可以定義一個協(xié)議,然后定義一個類遵循這個協(xié)議,在這個類的.m文件里實現(xiàn)這個協(xié)議中的方法。這樣不需要在.h中聲明,也可以在其他類中調(diào)用該類對應(yīng)協(xié)議中的方法。如下:

  • 定義協(xié)議
#import <Foundation/Foundation.h>
@class HWWashDevice;
@protocol HWWashDeviceParserProtocol <NSObject>
@required
- (void)hw_ParseWashDevice:(HWWashDevice *)device;
@end
  • 對應(yīng)方法中實現(xiàn)
@implementation HWDeviceParser
+ (instancetype)defaultParser
{
    HWDeviceParser *parser = [[HWDeviceParser alloc] init];
    return parser;
}
- (void)hw_ParseWashDevice:(HWWashDevice *)device
{
    //解析洗衣機屬性
    ...
    ...
    ...
}
  • 對該方法的調(diào)用
@interface HWWashDevice ()
@property (strong, nonatomic) id<HWWashDeviceParserProtocol> attributeparser;
@end

- (void)setUp
{
    self.attributeparser = [HWDeviceParser defaultParser];
    ...
}

/**
 *  設(shè)備屬性狀態(tài)變化
 *
 *  @param device     設(shè)備對象
 *  @param attributes 屬性發(fā)生變化的集合
 */
- (void)device:(uSDKDevice *)device didUpdateVlaueForAttributes:(NSArray<uSDKDeviceAttribute *> *)attributes
{
    NSLog(@"todo:%@", attributes);
    [super device:device didUpdateVlaueForAttributes:attributes];
   

之所以有這樣的設(shè)計,是因為要將共同的行為抽象出來:不同的類有不同的作用和特征,這也是面向?qū)ο蟮奶攸c,但是即使千差萬別,還是會有某些相似點的,這些相似的地方就可以抽象出來做成協(xié)議。
其關(guān)系如下圖:

協(xié)議關(guān)系.jpeg

那么我們就可以將各個類的協(xié)議統(tǒng)一放在一個協(xié)議類里(例如把不同種類的菜都放在做菜協(xié)議里),不同的類遵循不同的協(xié)議(不同的廚師完成不同的具體菜品),這樣在實現(xiàn)功能時我們只需在協(xié)議里尋找對應(yīng)方法(具體菜品),然后找到遵循此協(xié)議的類(菜品對應(yīng)的廚師),就可以實現(xiàn)具體功能,使代碼邏輯更加清晰。

在一個完全組件化的項目中,關(guān)系如下圖。

組件化的協(xié)議實現(xiàn)方式.jpeg

定義一個基礎(chǔ)協(xié)議,協(xié)議中包含很多相關(guān)方法。例如菜單協(xié)議,內(nèi)包含很多具體菜名。然后有若干的類(廚師),遵循該協(xié)議,實現(xiàn)部分對應(yīng)方法。使用字典的方式進行組件化注冊。在公共部分,根據(jù)協(xié)議找到實現(xiàn)的Class。并使用class實例執(zhí)行方法。

組件中只需要開放protocol與service即可,其他的所有內(nèi)容在內(nèi)部實現(xiàn),不做開放。
而公共部分只需要找到需要的protocol,即可實現(xiàn)對應(yīng)方法。

實例
  • 協(xié)議部分
    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;
    
  • 實現(xiàn)部分:
    傳統(tǒng)方式遵循該協(xié)議,并實現(xiàn)協(xié)議對應(yīng)方法。
    RAC 實現(xiàn)方式如下:

    // 不需要遵循該協(xié)議。而是創(chuàng)建時傳入該協(xié)議使之持有。
    - (instancetype)initWithServices:(id<MSViewModelServices>)services;
    

    初始化時注冊代理實現(xiàn)方法。

    - (void)registerNavigationHooks {
      @weakify(self)
      // 使用RAC監(jiān)測方法調(diào)用,當(dāng)方法調(diào)用時運行block內(nèi)部代碼,實際上就是協(xié)議方法的具體實現(xiàn)。
      [[(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]];
       }];
    }
    
  • 調(diào)用
    最后 viewModel 中再持有一份這個協(xié)議。
    利用如下方式調(diào)用:

    [self.viewModel.services pushViewModel:model animated:YES];
    
協(xié)議用于做封裝

比如現(xiàn)在有一個MeetingUser的類,其中的有很多屬性方法,只有部分屬性及部分方法暴露出去。

//interface.h中
-  (void)getUser:(id<CustomProtocol>)user;

定義CustomProtocol協(xié)議,聲明準(zhǔn)備暴露出去的屬性(屬性的get方法)及方法。

@protocol  CustomProtocol

- (NSString *)getPropertyA;
- (NSString *)getPropertyB;
- (void)methodA;

原有的MeetingUser遵循該協(xié)議,實現(xiàn)其定義的方法(屬性等原方法不變)。
getUser中直接返回MeetingUser對象即可。對外來說只是一個id類型遵循CustomProtocol的對象。可以使用該對象直接執(zhí)行協(xié)議中方法。
以這樣的方式實現(xiàn)封裝。

代理

概念

為其他對象提供一種代理以控制對這個對象的訪問。
代理模式分為三部分:委托方,代理方,協(xié)議。

委托方:tableview
協(xié)議:UITableviewdelegate,UITableviewDatasource
代理方:遵循協(xié)議的controller。

可以使用tableview.delegate=self來使本控制器來做代理方。
也可以新建一個類,例如tableviewDelegate類A。實例化該類,tableview.delegate = A.init。使A的實例作為代理方。在A類中實現(xiàn)協(xié)議中的方法。

id<UItableviewDelegate> delegate
一個任意類型可以遵循該協(xié)議的具體對象。該實例可以作為變量,可以作為參數(shù)傳遞。該實例必然可以執(zhí)行協(xié)議中的方法。

總結(jié)

tableview 定義了一個協(xié)議 tableviewdelegate 和tableviewdatasource。tableview作為委托方,制定了一個方法列表,找人幫它實現(xiàn)。viewcontroller使用了tableview,那么必須要為tableview指定一個代理方,可以是自己,也可以再找一個。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容