几处常识性笔记

2021-07-22  本文已影响0人  大成小栈

1. NSArray 与 NSSet

关于内存

NSArray 为有序的集合,存储数据的方式是连续的,在内存空间中的后一个数据是紧接着前一个数据的;NSSet 为无序的集合,散列存储,在内存空间中并不一定是连续的。

处理效率

NSSet 底层使用hash实现,所以需要保证里面存储的对象必须唯一,而数组可以存储相同的几个对象。由于NSSet是用hash实现,所以它查询速度快,但是不能进行下标操作。而数组可以进行下标操作,查询时逐个比对,速度稍慢。

2. UIScrollView 滑动的原理

可滑动的原因

UIScrollView 继承于 UIView,UIView不能滑动,而它居然能滑动。看看它的定义,其中,有一个panGestureRecognize滑动手势:

// Change `panGestureRecognizer.allowedTouchTypes` to limit scrolling to a particular set of touch types.
@property(nonatomic, readonly) UIPanGestureRecognizer *panGestureRecognizer API_AVAILABLE(ios(5.0));
// `pinchGestureRecognizer` will return nil when zooming is disabled.
@property(nullable, nonatomic, readonly) UIPinchGestureRecognizer *pinchGestureRecognizer API_AVAILABLE(ios(5.0));
// `directionalPressGestureRecognizer` is disabled by default, but can be enabled to perform scrolling in response to up / down / left / right arrow button presses directly, instead of scrolling indirectly in response to focus updates.
@property(nonatomic, readonly) UIGestureRecognizer *directionalPressGestureRecognizer API_DEPRECATED("Configuring the panGestureRecognizer for indirect scrolling automatically supports directional presses now, so this property is no longer useful.", tvos(9.0, 11.0));

若把这个手势移除:

[theScrollView removeGestureRecognizer:theScrollView.panGestureRecognizer];

结果scrollView失去了滑动的效果,原来是panGestureRecognize来实现的滑动效果。

可滑动的原理

UIScrollView 在接收滑动手势时,其子视图是怎么达到一起移动效果的呢?首先,我们必须知道UIView的frame和bounds的区别:

frame是相对父视图坐标系来决定自己的位置和大小;
bounds是相对于自身坐标系的位置和尺寸的。

因此,bounds的origin值为基于自身的坐标系,当自身坐标系的位置被改变了,里面的子视图肯定得变化。bounds和panGestureRecognize就是实现UIScrollView滑动效果的关键技术点。

自定义一个scrollView

我们可以根据上面的原理,自定义一个MyScrollView:

看完是不是发现UIScrollView的滑动原理很简单!是的,就这么简单!

3. 响应链及其应用

概述

当我们点击屏幕之后到应用触发响应,这个过程中发生了什么?如何理解iOS的响应链机制,我们可以通过这个机制实现那些功能?本文将着重讲解iOS响应链机制。

点击屏幕到应用捕获事件
image

点击屏幕后,经过系统的一系列处理,我们的应用接收到source0事件,并从事件队列中取出事件对象,开始寻找真正响应事件的视图。

响应者寻找过程分析

寻找相应过程主要涉及到两个方法:

//判断点击的位置是不是在视图内
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;
//返回点击的视图
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;

我们构造了一个简单的视图层级,BlueView/YellowView是两个根节点视图,RedView是他们的父视图。效果如下:

我们点击一下BlueView,其事件传递效果如下图:

image

我们分析一下事件的传递机制。

如果到第4步先找的不是YellowView而是BlueView,则不会再去检查YellowView。

找到最终点击的视图之后开始执行响应逻辑。

事件响应过程

我们点击一下BuleView。

如果BuleView没有添加手势事件,则回调用BlueView的touches事件。

输入的日志:

2020-04-25 17:06:48.992130+0800 ResponderDemo[99230:899392] -[BlueView touchesBegan:withEvent:]
2020-04-25 17:06:48.996208+0800 ResponderDemo[99230:899392] -[BlueView touchesEnded:withEvent:]

如果BuleView也没有实现touches事件,那么则会调用父视图的touches事件。

输出日志如下:

2020-04-25 17:12:10.550668+0800 ResponderDemo[99522:904959] -[RedView touchesBegan:withEvent:]
2020-04-25 17:12:10.555622+0800 ResponderDemo[99522:904959] -[RedView touchesEnded:withEvent:]

如何获取响应链

UIResponder *nextResponder = self.buleView.nextResponder;
NSMutableString *pre = [NSMutableString stringWithString:@"--"];
NSLog(@"View3");
while (nextResponder) {
  NSLog(@"%@%@", pre, NSStringFromClass([nextResponder class]));
  [pre appendString:@"--"];
  nextResponder = nextResponder.nextResponder;
}
实践
  1. Alpha=0、子视图超出父视图的情况、userInteractionEnabled=NO、hidden=YES 视图会被忽略,不会调用hitTest
  2. 父视图被忽略后其所有子视图也会被忽略
点击穿透

平行视图:重新hitTest,返回想要点击的View

父子视图: 如果子视图是Button 将button的enable改为false。如果是view不要添加手势即可。

限定点击区域

题目:UIView所在的UIViewController怎么查找???😄

上一篇 下一篇

猜你喜欢

热点阅读