iOS中的事件响应链、单例模式、工厂模式、观察者模式
学习内容
欢迎关注我的iOS学习总结——每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary
iOS中事件传递和相应机制
iOS中的事件(主要有三类)
- 触摸事件(touch Event)
- 运动/加速计事件(motion Event)
- 远程控制事件(remote-control Event)
UIResponder(响应者对象)
iOS中只有继承了UIResponder的类才能接收并处理事件,称之为响应者对象。
为什么继承了UIResponder的类都能够接收并处理事件呢?
//UIResponder类提供了以下四个对象方法来处理触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
事件响应链
所有处理事件响应的类都是UIResponder的子类,响应者链是一个由不同对象组成的层次结构,其中的每个对象依次获得响应事件消息的机会,事件将沿着响应者链一直向下传递,直到该事件被接收并且处理
事件的传递和响应链
//事件传递是从第一响应者->UIApplication
View->ViewController->UIWindow->UIApplication->nil
//事件的响应是从UIApplication->FirstResponder
UIApplication->UIwindow->ViewController->View
- 可以通过[responder nextResponder]找到当前responder的下一个responder,持续这个过程,最后会找到UIApplication对象
- 通常情况下,在first responder(即用户所点击的view)就会处理事件请求,进入事件分发机制
几种继承关系
- UIWindow->UIView->UIResponder
- UIApplication->UIResponder
事件分发机制
- 第一响应者指的是当前接受触摸的响应者对象(通常是一个UIView对象),表示当前对象正在与用户进行交互,它是响应链的开端,响应链和事件分发机制都是为了找出第一响应者
- 当发生触摸操作后,系统会将该操作打包成一个UIEvent对象,并将其放入当前活动Application的事件队列(队列的特点是先进先出,先发生的事件先处理)
- UIApplication会从事件队列中取出事件并将其分发给当前应用的UIWindow对象
- UIwindow对象首先会使用hitTest:withEvent:方法寻找该触摸事件发生时所在的视图,histTest->view
- hitTest:withEvent:方法的处理流程
- 调用pointInside:withEvent:方法判断触摸点是否在当前视图内
- 如果返回no,则hitTest方法返回nil,如果返回yes,则向当前视图的所有子视图发送hitTest:withEvent消息
- 如果第一次有子视图返回非空对象,那么UIWindow对象调用的histTest:withEvent(UIWindow继承自UIView,UIView含有hitTest方法)方法返回该对象,如果所有的子视图都返回nil,那么histTest:withEvent方法返回自身
- 如果histTest:withEvent方法没有找到第一响应者或者第一响应者没有处理该事件,那么该事件就会沿着响应者链向上回溯,如果UIWindow对象和UIApplication对象都不能处理该事件,那么该事件就会被丢弃。
- 如果对事件响应需要有特殊的操作,那么可以重写hisTest:withEvent方法来实现
- UIView(或者继承自UIView的子类)不能接收触摸事件的三种情况
- UIView的userInteractionEnabled设置为NO(不可交互)
- UIView的hidden设置为YES(隐藏了UIView,父控件隐藏的话子控件也会被隐藏)
- alpha透明度<0.01(0~0.01)为透明
UIApplication的几种状态
- not Running(程序未启动状态)
- Inactive(未激活)程序在前台运行,但是没有接收到事件,在没有事件需要处理的情况下程序通常处于这个状态
- active(激活)程序在前台运行,并且接收到了事件
- Background(后台),程序在后台运行并且可以执行代码,大多数程序挂起到后台都会在这个状态停留一会,一段时间后会进入挂起(Suspended)状态,经过特殊处理的请求可以长期处于这个状态。
- Suspended(挂起),程序在后台运行但是不能执行代码,系统自动把程序变成这个状态并且不会发出通知,但是还在内存中运行,当系统遇到内存压力时,就会自动将程序从内存中清除,为前台程序提供更多的内存。
iOS中的设计模式
设计原则
- 单一职责原则
- 一个类只承担一个职责,如果一个类拥有了两种职责,那么需要考虑是否将这个类拆分开来,比如UITableViewCell,如果有多重样式的cell,那么我们应该考虑的是分成几种类型的cell去写,而不是在一个cell中实现多种类型
- 开闭原则
- 对软件实体的修改,最好使用扩展而非直接修改的方式
- 对类,函数,如果需要修改,尽量采用继承的方式来扩展类的功能,而不是直接修改类的代码(如果工程不是特别复杂的情况下,那么直接修改类的代码也可以)
- 里式替换原则
- 子类可以扩展父类的方法,但不应该重写父类的方法
- 接口隔离原则
- 对象不应被强迫依赖它不使用的方法
- 依赖倒置原则
- 高层模块不应该依赖底层模块,二者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象
- 迪米特法则
- 一个对象对另一个对象了解的越多,那么他们的耦合度就越高,当修改一个对象时,对另一个对象的影响就越大(一个对象应该对另一个对象保持最少的了解,尽量实现低耦合高内聚)
- 组合/聚合复用原则
- 尽量使用合成/聚合,在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分,新的对象通过对这些对象的委派达到复用已有功能的目的(尽量使用合成/聚合,不要使用继承)
- 单一职责原则
iOS开发中几种常用的设计模式
单例模式(两种实现方法)
//使用@synchronized保证线程安全的懒加载写法,但是由于@synchronized是互斥锁导致性能比较低
+ (Singleton *)sharedInstance {
@synchronized (self) {
if (!instance) {
instance = [[Singleton alloc] init];
}
}
return instance;
}
//使用GCD中的dispatch_once写法,同时满足了线程安全和静态分析器的要求
+ (Singleton *)sharedInstance {
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
instance = [[Singleton alloc] init];
});
return instance;
}
以上两种单例模式的实现都不能保证SingleTon是唯一的,因为通过[[Single alloc]init]方式创建仍然会创建出新的实例
创建绝对单例的方法
//通过拦截alloc方法来创建绝对单例
//new->alloc
//alloc->allocWithZone
//alloc方法的内部就是调用了allocWithZone方法,allocWithZone方法的作用就是申请空间创建对象并将创建的对象返回。
+ (instancetype)shareInstance
{
if (instance == nil) {
static dispatch_once_t once;
dispatch_once(&once, ^{
instance = [[Singleton alloc] init];
});
}
return instance;
} + (instancetype)allocWithZone:(struct _NSZone *)zone
{
if (instance == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
}
return instance;
}
工厂模式
//一个工厂类需要执行多个方法,可以将每个方法衍生出一个类继承自这个工厂类,实例化工厂类时根据传入的参数创建对应方法的实例
@implementation OperationFactory + (Operation *) createOperat:(char)operate{
Operation *oper = nil;
switch (operate) {
case '+':
{
oper = [[OperationAdd alloc] init];
break;
}
case '-':
{
oper = [[OperationSub alloc] init];
break;
}
case '*':
{
oper = [[OperationMul alloc] init];
break;
}
case '/':
{
oper = [[OperationDiv alloc] init];
break;
}
default:
break;
}
return oper;
}
@end
委托模式(这里只列出使用步骤,A为委托对象,B为代理对象)
类A接口为文件中创建协议,声明@requeired和@optional方法
类A添加一个属性,使用weak修饰(否则会造成循环引用)
@property (nonatomic,wead) id<协议名>delegate
类B接口文件/类扩展中遵守协议,并在实现文件中实现协议的required/optional方法
类B中创建一个类A对象,类A对象的delegate设置为self(类B自身)
在类A对象中调用[self.delegate 方法]
观察者模式(两种方式)
- 使用NSNotification通知实现
- 使用KVO(key,value,observer)键值观测实现
iOS中的事件响应链、单例模式、工厂模式、观察者模式的更多相关文章
- iOS事件响应链
首先,当发生事件响应时,必须知道由谁来响应事件.在IOS中,由响应者链来对事件进行响应,所有事件响应的类都是UIResponder的子类,响应者链是一个由不同对象组成的层次结构,其中的每个对象将依次获 ...
- iOS事件响应链(Responder Chain)
概述 在iOS中,视图的层级一般都是 父视图->添加各种子视图.这时候某个视图(子视图)上有个按钮,需要我们交互.但是有时候我们会发现无论如何都没有反应.这时候可能就是我们对iOS的事件传递响应 ...
- UI基础:事件.响应链 分类: iOS学习-UI 2015-07-03 19:51 1人阅读 评论(0) 收藏
UIEvent:事件,是由硬件捕捉的一个代表用户操作操作设备的对象. 事件分三类:触摸事件.晃动事件.远程控制事件. 触摸事件:用户通过触摸设备屏幕操作对象,.输入数据.支持多点触摸,包含1个到多个触 ...
- 追踪app崩溃率、事件响应链、Run Loop、线程和进程、数据表的优化、动画库、Restful架构、SDWebImage的原理
1.如何追踪app崩溃率,如何解决线上闪退 当 iOS设备上的App应用闪退时,操作系统会生成一个crash日志,保存在设备上.crash日志上有很多有用的信息,比如每个正在执行线程的完整堆栈 跟踪信 ...
- iOS-UIResponse之事件响应链及其事件传递
UIResponse之事件响应链及其事件传递 我们的App与用户进行交互,基本上是依赖于各种各样的事件.一个视图是一个事件响应者,可以处理点击等事件,而这些事件就是在UIResponder类中定义的. ...
- 响应者链条,iOS中touchs事件的处理流程。
用户在使用app的时候,会产生各样的事件.在iOS中的事件可以分为三种 触摸事件(Touch Event) 加速计事件(Accelerometer Event) 远程控制事件(Remote Contr ...
- 【Demo 0010】事件响应链
本章学习要点: 1. 熟悉iOS事件分发过程以及事件响应链; 2. 掌握基本事件响应方法(单击,双击): 3. 掌握基本手势处理方法:
- Objective-C 事件响应链
苹果app使用响应者对象(responder object)来接收和处理事件.响应者对象是NSResponder及其子类的实例,如NSView.NSViewController和NSApplicati ...
- 1.0 iOS中的事件
本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人 “简书” 在用户使用app过程中,会产生各种各样的事件,iOS中的事件可以分为3大类型: UIK ...
随机推荐
- ATmega328P定时器详解
写这篇文章,纯粹是想为博客拉点点击量.在博客园,游客访问好像是不计入阅读量的,而作为一个十八线博主,注册用户的访问应该以搜索引擎为主,博客园首页为次,个位数的粉丝就别谈了. 所以,希望各位从搜索引擎点 ...
- 牛客网 - vivo2020届春季
牛客网 - vivo2020届春季 1.[编程题]手机屏幕解锁模式 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M 现有一个 3x3 规格的 Android ...
- Jmeter系列(3)- Jmeter安装目录介绍
如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html Jmeter安装目录说明 bin:包含 ...
- 【MyBatis深入剖析】应用分析与最佳实践(下)
MyBatis编程式开发 MyBatis编程式开发步骤 MyBatis和MySQL Jar包依赖 全局配置文件mybatis-config.xml 映射器Mapper.xml Mapper接口 编程式 ...
- Oracle数据库排序后分页查询数据错误问题解决
一.问题描述:根据更新时间倒序排序然后分页查询数据,但是点击分页操作的时候,会出现数据重复看似没有操作的情况 二.问题错误原因分析 分页查询的SQL语句: select * FROM (select ...
- tp5--模型关联
来源于:https://blog.csdn.net/u012600104/article/details/78927629 先说明,模型关联和join管理是不一样的,用文章和评论的关系来举例.(一对多 ...
- 十七, Oracle索引约束
管理索引-原理介绍 索引是用于加速数据存取的数据对象.合理的使用索引可以大大降低i/o次数,从而提高数据访问性能. 单列索引 适当的索引对于大型数据库的性能有不错的提升, 但在创建索引时要小心.选择字 ...
- 在IBM Cloud中运行Fabric
文章目录 打包智能合约 创建IBM Cloud services 创建fabric网络 创建org和相应的节点 创建order org和相应节点 创建和加入channel 导入智能合约 上篇文章我们讲 ...
- 还在写CURD?试试这款基于mybatis-plus的springboot代码生成器
目录 ⚡Introduction ✔️Release Features Quick Start Examples 1.Controller模板代码示例 2.Service模板代码示例 3.Servic ...
- 在线教育项目-day05【课程分类管理-添加课程分类】
1.引入依赖 之前测试EasyExcel已经引入过了 2.利用代码生成器生成结构 我们做的只需要更改代码生成器的数据库表即可 3.运行代码生成器 4.书写代码 1.controller @RestCo ...