编码篇-OC跨多层UI事件传递处理

前言

在 iOS 中,对象间的交互模式大概有这几种:直接 property 传值、delegate、KVO、block、protocol、多态、Target-Action 等等,本文介绍的是一种基于 UIResponder 对象交互方式,简而言之,就是 通过在 UIResponder上挂一个 category,使得事件和参数可以沿着 responder chain 逐步传递。对于那种 subviews 特别多,事件又需要层层传递的层级视图特别好用,但是,缺点也很明显,必须依赖于 UIResponder 对象。

在项目开发中相信很多朋友都遇到过多层级view,事件抛出至VC处理的问题。 一般的处理方法都是使用 代理、回调、属性传值,可是多层级的View会让整个流程非常痛苦和难于维护。

多层级View的UI事件处理有较好的方案,比如采用ReactiveCocoa、使用通知等等。可是ReactiveCocoa 的学习成本比较高,通知的话注册通知,发送通知也是比较麻烦。

场景

一个VC的View上放了很多的子视图,(中间有很多层)我们点击了最上面的一个Button,需要把Button的tag传到 VC中

Paste_Image.png

知识点( 此处不讨论代理回调和通知。)

  • UIResponder类定义了一个对象接口用来响应和处理事件, 它是UIApplication, UIView以及UIView的子类(包括UIWindow)的父类, 这些类的实例对象被称为响应对象或者响应者。
  • 然后UIResponder对象有一个重要的属性叫做nextResponder, 下一个响应者,可以保证找到当前view的事件的接收者
  • 可以建立一个 UIResponder的类别,在类别中扩建一个方法,使所有的子类都可以调用.
  • 在需要处理的地方重写 UIResponder的类别中的这个方法即可使整个传递终结掉。大大优化了整个事件处理过程。

由上至下的事件传递实现方法

#import "UIResponder+Router.h"
@implementation UIResponder (Router)
- (void)routerWithEventName:(NSString *)eventName userInfo:(NSDictionary *)userInfo 
{
     if (self.nextResponder) { 
    [[self nextResponder] routerWithEventName:eventName userInfo:userInfo]; 
    }
}
@end

第一个参数是事件名称, 第二个参数是需要传递的参数信息
看起来这样一个方法会陷入死循环, 其实不然, 当self.nextResponder向上一直找到UIApplication都还不能响应事件的时候, 
系统就会自动丢弃这个事件

而当我控制器中重写这个方法的时候, 相当于重写父类方法的时候,
那么系统就会走子类的方法, 那么参数就直接传递给控制器了

*控制器中重写父类方法*
- (void)routerWithEventName:(NSString *)eventName userInfo:(NSDictionary *)userInfo
  { 
      if ([eventName isEqualToString:YFTransferNameEvent]) { 
    NSString * name = userInfo[YFUserName]; 
    NSLog(@"用户的姓名为:%@",name); 
  }    
}

*cell中Button的点击事件*
- (void)buttonClickAction:(UIButton *)sender
 { 
      [sender routerWithEventName:YFTransferNameEvent 
    userInfo:@{ YFUserName:[self userName], }];
  }

Paste_Image.png

也就是说, button将事件处理传递给nextResponder, 也就是cell, cell没有重写父类方法, 继续将事件传递给tableView, tableView也没有重写父类方法, 于是将事件处理传递给控制器的view,控制器的view也没有重写父类方法, 于是将事件处理传递给控制器, 控制器重写了父类方法, 于是就走控制器重写的方法, 进行事件处理, 事件就成功地从button传到了控制器.

跨层处理事件后的回执

cell把事件传递给 VC后VC处理后怎么把结果返回给Cell使用呢,两个方式:

  • 在上述的方法中把需要接受结果的对象指针传过去,比如cell上一个按钮要设置背景图片,VC取完图片在方法中获取到这个按钮的指针,VC通过这个指针通过直接操作内存的方式设置这个按钮即可
  • 在类别的方法中定义 Block回调函数,cell发送事件,VC处理完后,通过Block把处理结果发送给 cell,供cell使用,这样是最简单的。

值得注意的是,这样的事件传递处理方法,最常见的Bug就是当前试图初始化后确实存在,但是没有加载到父视图上,才导致的方法无法触发。

参考文章

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏python爬虫实战之路

python操作Excel,你觉得哪个库更好呢?

每一个Excel数据文件从上至下分为三个层级的对象: workbook: 每一个Excel文件就是一个workbook。 sheet: 每一个workbook中...

7.4K30
来自专栏HTML5学堂

2016.07 第2周 群问题分享

HTML+CSS 移动端中1px的边框如何实现 2016.07.04~2016.07.08 核心概念: viewport、CSS3属性 参考答案: 一、通过设置...

29960
来自专栏破晓之歌

vue2.5入门(推荐,差代码) 原

11220
来自专栏PHP在线

jQuery学习笔记

jQuery大部分功能需要根据文档的DOM模型来工作,首先需要正确地解析到整个文档的DOM模型结构。使用jQuery需要在整个文档被浏览器完全加载后才开始进行。

11620
来自专栏青玉伏案

IOS开发之自定义Button(集成三种回调模式)

  前面在做东西的时候都用到了storyboard,在今天的代码中就纯手写代码自己用封装个Button。这个Button继承于UIView类,在封装的时候用上啦...

26480
来自专栏魂祭心

原 利用Appdomain动态加载程序集,

37180
来自专栏码生

React Native 大纲

8930
来自专栏iKcamp

React 深入系列3:Props 和 State

文:徐超,《React进阶之路》作者 授权发布,转载请注明作者及出处 ---- React 深入系列3:Props 和 State React 深...

41060
来自专栏web前端-

rem和em小插曲

1.对em来说,它的大小是相对于父层font-size来改变,但是如果其自身有font-size属性的话,em会优先考虑自身的font-size;

10120
来自专栏c#开发者

selenum参考手册中文翻译

Added by SpringSideTeam, last edited by SpringSideTeam on 2006-11-23  (view chan...

29560

扫码关注云+社区

领取腾讯云代金券