hw-1

iOS事件的分发机制和响应者链(Swift)

iOS事件的分发机制和响应者链(Swift)

事件沿着具体的路径进行传递,一直到发现对象能够处理该事件,首先,UIApplication单例对象会将该事件将被传递给window对象,window对象会使用hitTest:withEvent:方法来递归的寻找操作初始点所在的view,该视图就称之为hit-test view,寻找hit-test view过程称为hit-testing.

分发机制(Hit-Testing)
   iOS使用hit-testing来找到触摸点所在的视图。hit-testing将会检测是否触摸事件在相关视图的显示区域之内。如果在,将递归检测当前视图的所有子视图。视图层级中最底层的view如果包含触摸点将成为hit-test view.在iOS确认了hit-test view之后,将传递触摸世界给对应的视图进行处理。

hitTest:withEvent:方法的处理流程如下:调用当前view的pointInside:withEvent:方法来判定触摸点是否在当前view内部,如果返回false,则hitTest:withEvent:返回nil;如果返回true,则向当前view内的subViews发送hitTest:withEvent:消息,所有subView的遍历顺序是从数组的末尾向前遍历,直到有subView返回非空对象或遍历完成。如果有subView返回非空对象,hitTest方法会返回这个对象,如果每个subView返回都是nil,则返回自己。

许多类型的事件都依赖于响应者链进行事件的传递。响应者链关联着一系列的响应者对象,由第一个响应者对象开始一直到application对象结束,如果第一个响应者不能够处理事件,事件将会被传递到响应者链中的下一个响应者对象。

一个响应者对象是能够处理和响应事件的对象,UIResponder类是所有响应者对象的基类,它不仅仅定义了事件处理的接口而且还有共有的响应者行为。UIApplication, UIViewController, UIView等类的实例都是响应者对象,这意味着所有的视图(all views)和大多数的关键视图控制器对象都是响应者。但是要注意核心动画中的层(layer)不是响应者

传递链:由系统向离用户最近的view传递。UIKit –> active app’s event queue –> window –> root view –>……–>lowest view

响应链:由离用户最近的view向系统传递。initial view –> super view –> …..–> view controller –> window –> Application

开发中覆盖hitTest:withEvent:的一些用途:

1:增加视图的触摸区域

     比如:按钮本身大小为20_20,但是太小不便操作,我们可以通过自定义UIButton,重写hitTest方法,增加点击区域:下面是添加了一个20_20的按钮,然后通过操作hitTest方法,实现100*100区域内可点击,即在每个方向增加40,具体实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyButton: UIButton {
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
if !self.userInteractionEnabled || self.hidden || self.alpha == 0 {
return nil
}

if CGRectContainsPoint(CGRectInset(self.bounds, -40, -40), point){
for subview in self.subviews.reverse() {
let convertPoint = subview.convertPoint(point, fromView:self)
if let sview = subview.hitTest(convertPoint, withEvent: event) {
return sview
}
}
return self
}
return nil
}
}

2:实现传递事件到点击视图之下的视图

有的时候对于一个视图忽略触摸事件并传递给下面的视图是很重要的。例如,假设一个透明的视图覆盖在应用内所有视图的最上面。覆盖层有子视图应该相应触摸事件的一些控件和按钮。但是触摸覆盖层的其他区域应该传递给覆盖层下面的视图。为了完成这个行为,覆盖层需要覆盖hitTest:withEvent:方法来返回包含触摸点的子视图中的一个,然后其他情况返回nil,包括覆盖层包含触摸点的情况:

1
2
3
4
5
6
7
8
9
class SHView: UIView {
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
var hitTestView = super.hitTest(point, withEvent:event)
if hitTestView == self{
hitTestView = nil
}
return hitTestView;
}
}

3:超出父视图区域部分响应事件

首先看一下页面效果:当前页面上有3个控件,紫色视图是红色视图的子视图,红色视图是灰色视图的子视图。最上面是一个按钮,方便我们进行测试:现在我们要实现点击红色视图之外的紫色区域能够响应事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class TestView: UIView {
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
super.hitTest(point, withEvent: event)
return overlapHitTest(point, withEvent: event)
}
}

extension UIView{
func overlapHitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
// We should not send touch events for hidden or transparent views, or views with userInteractionEnabled set to NO;
if !self.userInteractionEnabled || self.hidden || self.alpha == 0 {
return nil
}
// If touch is inside self, self will be considered as potential result.
var hitView: UIView? = self
if !self.pointInside(point, withEvent: event) {
if self.clipsToBounds {
return nil
} else {
hitView = nil
}
}
// Check recursively all subviews for hit. If any, return it.
for subview in self.subviews.reverse() {
let insideSubview = self.convertPoint(point, toView: subview)
if let sview = subview.overlapHitTest(insideSubview, withEvent: event) {
return sview
}
}
// Else return self or nil depending on result from step 2.
return hitView
}
}

jenkins忘记管理员账号登录密码如何修改管理员账号

jenkins忘记管理员账号登录密码如何修改管理员账号

1
2
3
4
5
6
7
8
(1)用命令打开:
sudo vi /Users/Shared/Jenkins/Home/users/admin/config.xml 
(2)找到<passwordHash>节点
将节点内的<passwordHash>#jbcrypt:$2a$10$lbyWNEX8qFyS47ddBYHgHOOIdnsijELWhprkGA0aZQRfapnzGeVl6</passwordHash>的值改为:
#jbcrypt:$2a$10$DdaWzN64JgUtLdvxWIflcuQu2fgrrMSAMabF5TSrGK5nXitqK9ZMS  (该字符串默认密码为6个1)
注意前后不要输入空格。按Esc键->:->wq保存。
3/重启Jenkins:jenkins restart
4/打开localhost:8080,输入管理员账号,密码为6个1,点击【登录】登录成功

iOS 数组集合操作(交集,并集,差集,子集)

iOS 数组集合操作(交集,并集,差集,子集)

1
2
3
4
5
6
7
8
9
NSArray *array1 = @[@"1",@"2",@"3"];
NSArray *array2 = @[@"1",@"5",@"6"];
NSMutableSet *set1 = [NSMutableSet setWithArray:array1];
NSMutableSet *set2 = [NSMutableSet setWithArray:array2];

[set1 unionSet:set2]; //取并集后 set1中为1,2,3,5,6
[set1 intersectSet:set2]; //取交集后 set1中为1
[set1 minusSet:set2]; //取差集后 set1中为2,3,5,6

PHAsset框架里面的PHImageManager获取原图内存过高崩溃

在iOS开发中我们有时候需要从Photos框架中获取的phasset转化为uiimage,PHAsset框架给我们提供了两个方法一个是PHImageManager的requestImageForAsset这个方法是通过Phasset直接获取到uiimage对象,可能很多人会使用这个方法,但是这有一个巨坑,就是你转化完之后,获得了uiimage对象,但是当你的图片很大的时候,那么极有可能会导致app崩溃
还有一个方法是PHImageManager的requestImageDataForAsset方法,这个方法是吧Phasset转化为nsdata对象,我们拿到nsdata对象可以转化为uiimage对象,这样的话可以解决内存暴涨的问题.
原因是因为requestImageForAsset会对图片进行渲染,所以导致内存暴涨不下,而requestImageDataForAsset则是直接返回二进制数据,所以内存不会出现暴涨的现象.

Attempt to delete row containing first responder that refused to resign

Attempt to delete row containing first responder that refused to resign

I’ve never seen that message before, but my immediate impulse if I were to see it would be: try delayed performance. Even something as simple as this might be an interesting experiment:

1
2
3
4
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView deleteRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
});