当前位置: 首页 > 编程日记 > 正文

iOS事件处理,看我就够了~

该文章属于<简书 — 刘小壮>原创,转载请注明:

<简书 — 刘小壮> https://www.jianshu.com/p/b0884faae603


好久没写博客了,前后算起来刚好有一年了。这期间博客也不是一直没变化,细心的同学应该能发现,我一直在回复评论区和私信的问题,还更新了好几篇之前的博客。

去年是有意义的一年,从各个方面我也学到了不少的东西,也不局限于技术方面。很多人都写年终总结,我比较懒就不写了,内心做自我总结吧,哈哈?。

回归正题,在项目中经常会遇到各种手势或者点击事件处理之类的,这些都属于响应事件处理。但是很多人对iOS中的响应事件处理并不清楚,经常会遇到手势冲突、事件不响应之类的问题,所以就去查博客。
但是现在很多博客写的并不是很完整,或者说质量并不高,我这两天抽时间把我所学习和理解的iOS事件处理写出来,供各位参考。


博客配图

UIResponder

UIResponder是iOS中用于处理用户事件的API,可以处理触摸事件、按压事件(3D touch)、远程控制事件、硬件运动事件。可以通过touchesBeganpressesBeganmotionBeganremoteControlReceivedWithEvent等方法,获取到对应的回调消息。UIResponder不只用来接收事件,还可以处理和传递对应的事件,如果当前响应者不能处理,则转发给其他合适的响应者处理。

应用程序通过响应者来接收和处理事件,响应者可以是继承自UIResponder的任何子类,例如UIViewUIViewControllerUIApplication等。当事件来到时,系统会将事件传递给合适的响应者,并且将其成为第一响应者。

第一响应者未处理的事件,将会在响应者链中进行传递,传递规则由UIRespondernextResponder决定,可以通过重写该属性来决定传递规则。当一个事件到来时,第一响应者没有接收消息,则顺着响应者链向后传递。

查找第一响应者

基础API

查找第一响应者时,有两个非常关键的API,查找第一响应者就是通过不断调用子视图的这两个API完成的。

调用方法,获取到被点击的视图,也就是第一响应者。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

hitTest:withEvent:方法内部会通过调用这个方法,来判断点击区域是否在视图上,是则返回YES,不是则返回NO

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;

查找第一响应者

应用程序接收到事件后,将事件交给keyWindow并转发给根视图,根视图按照视图层级逐级遍历子视图,并且遍历的过程中不断判断视图范围,并最终找到第一响应者。

keyWindow开始,向前逐级遍历子视图,不断调用UIViewhitTest:withEvent:方法,通过该方法查找在点击区域中的视图后,并继续调用返回视图的子视图的hitTest:withEvent:方法,以此类推。如果子视图不在点击区域或没有子视图,则当前视图就是第一响应者。

hitTest:withEvent:方法中,会从上到下遍历子视图,并调用subViewspointInside:withEvent:方法,来找到点击区域内且最上面的子视图。如果找到子视图则调用其hitTest:withEvent:方法,并继续执行这个流程,以此类推。如果子视图不在点击区域内,则忽略这个视图及其子视图,继续遍历其他视图。

可以通过重写对应的方法,控制这个遍历过程。通过重写pointInside:withEvent:方法,来做自己的判断并返回YESNO,返回点击区域是否在视图上。通过重写hitTest:withEvent:方法,返回被点击的视图。

此方法在遍历视图时,忽略以下三种情况的视图,如果视图具有以下特征则忽略。但是视图的背景颜色是clearColor,并不在忽略范围内。

  1. 视图的hidden等于YES。
  2. 视图的alpha小于等于0.01。
  3. 视图的userInteractionEnabled为NO。

如果点击事件是发生在视图外,但在其子视图内部,子视图也不能接收事件并成为第一响应者。这是因为在其父视图进行hitTest:withEvent:的过程中,就会将其忽略掉。

事件传递

传递过程

  1. UIApplication接收到事件,将事件传递给keyWindow
  2. keyWindow遍历subViewshitTest:withEvent:方法,找到点击区域内合适的视图来处理事件。
  3. UIView的子视图也会遍历其subViewshitTest:withEvent:方法,以此类推。
  4. 直到找到点击区域内,且处于最上方的视图,将视图逐步返回给UIApplication
  5. 在查找第一响应者的过程中,已经形成了一个响应者链。
  6. 应用程序会先调用第一响应者处理事件。
  7. 如果第一响应者不能处理事件,则调用其nextResponder方法,一直找响应者链中能处理该事件的对象。
  8. 最后到UIApplication后仍然没有能处理该事件的对象,则该事件被废弃。

模拟代码

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {if (self.alpha <= 0.01 || self.userInteractionEnabled == NO || self.hidden) {return nil;}BOOL inside = [self pointInside:point withEvent:event];if (inside) {NSArray *subViews = self.subviews;// 对子视图从上向下找for (NSInteger i = subViews.count - 1; i >= 0; i--) {UIView *subView = subViews[i];CGPoint insidePoint = [self convertPoint:point toView:subView];UIView *hitView = [subView hitTest:insidePoint withEvent:event];if (hitView) {return hitView;}}return self;}return nil;
}

示例

事件传递示例

如上图所示,响应者链如下:

  1. 如果点击UITextField后其会成为第一响应者。
  2. 如果textField未处理事件,则会将事件传递给下一级响应者链,也就是其父视图。
  3. 父视图未处理事件则继续向下传递,也就是UIViewControllerView
  4. 如果控制器的View未处理事件,则会交给控制器处理。
  5. 控制器未处理则会交给UIWindow
  6. 然后会交给UIApplication
  7. 最后交给UIApplicationDelegate,如果其未处理则丢弃事件。

事件通过UITouch进行传递,在事件到来时,第一响应者会分配对应的UITouchUITouch会一直跟随着第一响应者,并且根据当前事件的变化UITouch也会变化,当事件结束后则UITouch被释放。

UIViewController没有hitTest:withEvent:方法,所以控制器不参与查找响应视图的过程。但是控制器在响应者链中,如果控制器的View不处理事件,会交给控制器来处理。控制器不处理的话,再交给View的下一级响应者处理。

注意

  1. 在执行hitTest:withEvent:方法时,如果该视图是hidden等于NO的那三种被忽略的情况,则改视图返回nil
  2. 如果当前视图在响应者链中,但其没有处理事件,则不考虑其兄弟视图,即使其兄弟视图和其都在点击范围内。
  3. UIImageViewuserInteractionEnabled默认为NO,如果想要UIImageView响应交互事件,将属性设置为YES即可响应事件。

事件控制

事件拦截

有时候想让指定视图来响应事件,不再向其子视图继续传递事件,可以通过重写hitTest:withEvent:方法。在执行到方法后,直接将该视图返回,而不再继续遍历子视图,这样响应者链的终端就是当前视图。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {return self;
}

事件转发

在开发过程中,经常会遇到子视图显示范围超出父视图的情况,这时候可以重写该视图的pointInside:withEvent:方法,将点击区域扩大到能够覆盖所有子视图。

扩大响应区域

假设有上面的视图结构,SuperViewSubview超出了其视图范围,如果点击Subview在父视图外面的部分,则不能响应事件。所以通过重写pointInside:withEvent:方法,将响应区域扩大为虚线区域,包含SuperView的所有子视图,即可让子视图响应事件。

事件逐级传递

如果想让响应者链中,每一级UIResponder都可以响应事件,可以在每级UIResponder中都实现touches并调用super方法,即可实现响应者链事件逐级传递。

只不过这并不包含UIControl子类以及UIGestureRecognizer的子类,这两类会直接打断响应者链。

Gesture Recognizer

如果有事件到来时,视图有附加的手势识别器,则手势识别器优先处理事件。如果手势识别器没有处理事件,则将事件交给视图处理,视图如果未处理则顺着响应者链继续向后传递。

手势识别

当响应者链和手势同时出现时,也就是既实现了touches方法又添加了手势,会发现touches方法有时会失效,这是因为手势的执行优先级是高于响应者链的。

事件到来后先会执行hitTestpointInside操作,通过这两个方法找到第一响应者,这个在上面已经详细讲过了。当找到第一响应者并将其返回给UIApplication后,UIApplication会向第一响应者派发事件,并且遍历整个响应者链。如果响应者链中能够处理当前事件的手势,则将事件交给手势处理,并调用touchescalcelled方法将响应者链取消。

UIApplication向第一响应者派发事件,并且遍历响应者链查找手势时,会开始执行响应者链中的touches系列方法。会先执行touchesBegantouchesMoved方法,如果响应者链能够继续响应事件,则执行touchesEnded方法表示事件完成,如果将事件交给手势处理则调用touchesCancelled方法将响应者链打断。

根据苹果的官方文档,手势不参与响应者链传递事件,但是也通过hitTest的方式查找响应的视图,手势和响应者链一样都需要通过hitTest方法来确定响应者链的。在UIApplication向响应者链派发消息时,只要响应者链中存在能够处理事件的手势,则手势响应事件,如果手势不在响应者链中则不能处理事件。

Apple UIGestureRecognizer Documentation

UIControl

根据上面的手势和响应者链的处理规则,我们会发现UIButton或者UISlider等控件,并不符合这个处理规则。UIButton可以在其父视图已经添加tapGestureRecognizer的情况下,依然正常响应事件,并且tap手势不响应。

UIControl

UIButton为例,UIButton也是通过hitTest的方式查找第一响应者的。区别在于,如果UIButton是第一响应者,则直接由UIApplication派发事件,不通过Responder Chain派发。如果其不能处理事件,则交给手势处理或响应者链传递。

不只UIButton是直接由UIApplication派发事件的,所有继承自UIControl的类,都是由UIApplication直接派发事件的。

Apple UIControl Documentation

事件传递优先级

测试

为了有依据的推断响应事件的实现和传递机制,我们做以下测试。

示例1

示例1

假设RootViewSuperViewButton都实现touches方法,并且Button添加buttonAction:action,点击button后的调用如下。

RootView -> hitTest:withEvent:
RootView -> pointInside:withEvent:
Button -> hitTest:withEvent:
Button -> pointInside:withEvent:
RootView -> hitTest:withEvent:
RootView -> pointInside:withEvent:Button -> touchesBegan:withEvent:
Button -> touchesEnded:withEvent:
Button -> buttonAction:
示例2

还是上面的视图结构,我们给RootView加上UITapGestureRecognizer手势,并且通过tapAction:方法接收回调,点击上面的SuperView后,方法调用如下。

RootView -> hitTest:withEvent:
RootView -> pointInside:withEvent:
Button -> hitTest:withEvent:
Button -> pointInside:withEvent:
SuperView -> hitTest:withEvent:
SuperView -> pointInside:withEvent:
RootView -> hitTest:withEvent:
RootView pointInside:withEvent:RootView -> gestureRecognizer:shouldReceivePress:
RootView -> gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:
SuperView -> touchesBegan:withEvent:
RootView -> gestureRecognizerShouldBegin:
RootView -> tapAction:
SuperView -> touchesCancelled:
示例3

示例3

上面的视图中Subview1Subview2Subview3是同级视图,都是SuperView的子视图。我们给Subview1加上UITapGestureRecognizer手势,并且通过subView1Action:方法接收回调,点击上面的Subview3后,方法调用如下。

SuperView -> hitTest:withEvent:
SuperView -> pointInside:withEvent:
Subview3 -> hitTest:withEvent:
Subview3 -> pointInside:withEvent:
SuperView -> hitTest:withEvent:
SuperView -> pointInside:withEvent:Subview3 -> touchesBegan:withEvent:
Subview3 -> touchesEnded:withEvent:

通过上面的例子来看,虽然Subview1Subview3的下面,并且添加了手势,点击区域是在Subview1Subview3两个视图上的。但是由于经过hitTestpointInside之后,响应者链中并没有Subview1,所以Subview1的手势并没有被响应。

分析

根据我们上面的测试,推断iOS响应事件的优先级,以及整体的响应逻辑。

当事件到来时,会通过hitTestpointInside两个方法,从Window开始向上面的视图查找,找到第一响应者的视图。找到第一响应者后,系统会判断其是继承自UIControl还是UIResponder,如果是继承自UIControl,则直接通过UIApplication直接向其派发消息,并且不再向响应者链派发消息。

如果是继承自UIResponder的类,则调用第一响应者的touchesBegin,并且不会立即执行touchesEnded,而是调用之后顺着响应者链向后查找。如果在查找过程中,发现响应者链中有的视图添加了手势,则进入手势的代理方法中,如果代理方法返回可以响应这个事件,则将第一响应者的事件取消,并调用其touchesCanceled方法,然后由手势来响应事件。

如果手势不能处理事件,则交给第一响应者来处理。如果第一响应者也不能响应事件,则顺着响应者链继续向后查找,直到找到能够处理事件的UIResponder对象。如果找到UIApplication还没有对象响应事件的话,则将这次事件丢弃。

接收事件深度剖析

UIApplication接收到响应事件之前,还有更复杂的系统级的处理,处理流程大致如下。

  1. 系统通过IOKit.framework来处理硬件操作,其中屏幕处理也通过IOKit完成(IOKit可能是注册监听了屏幕输出的端口)

当用户操作屏幕,IOKit收到屏幕操作,会将这次操作封装为IOHIDEvent对象。通过mach port(IPC进程间通信)将事件转发给SpringBoard来处理。

  1. SpringBoard是iOS系统的桌面程序。SpringBoard收到mach port发过来的事件,唤醒main runloop来处理。

main runloop将事件交给source1处理,source1会调用__IOHIDEventSystemClientQueueCallback()函数。

  1. 函数内部会判断,是否有程序在前台显示,如果有则通过mach portIOHIDEvent事件转发给这个程序。

如果前台没有程序在显示,则表明SpringBoard的桌面程序在前台显示,也就是用户在桌面进行了操作。
__IOHIDEventSystemClientQueueCallback()函数会将事件交给source0处理,source0会调用__UIApplicationHandleEventQueue()函数,函数内部会做具体的处理操作。

  1. 例如用户点击了某个应用程序的icon,会将这个程序启动。

应用程序接收到SpringBoard传来的消息,会唤醒main runloop并将这个消息交给source1处理,source1调用__IOHIDEventSystemClientQueueCallback()函数,在函数内部会将事件交给source0处理,并调用source0__UIApplicationHandleEventQueue()函数。
__UIApplicationHandleEventQueue()函数中,会将传递过来的IOHIDEvent转换为UIEvent对象。

  1. 在函数内部,调用UIApplicationsendEvent:方法,将UIEvent传递给第一响应者或UIControl对象处理,在UIEvent内部包含若干个UITouch对象。
Tips

source1runloop用来处理mach port传来的系统事件的,source0是用来处理用户事件的。
source1收到系统事件后,都会调用source0的函数,所以最终这些事件都是由source0处理的。

小技巧

在开发中,有时会有找到当前View对应的控制器的需求,这时候就可以利用我们上面所学,根据响应者链来找到最近的控制器。

UIResponder中提供了nextResponder方法,通过这个方法可以找到当前响应环节的上一级响应对象。可以从当前UIView开始不断调用nextResponder,查找上一级响应者链的对象,就可以找到离自己最近的UIViewController

示例代码:

- (UIViewController *)parentController {UIResponder *responder = [self nextResponder];while (responder) {if ([responder isKindOfClass:[UIViewController class]]) {return (UIViewController *)responder;}responder = [responder nextResponder];}return nil;
}

相关文章:

ISO9000机房管理办法

1 总则<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />1.1制定目的(1) 规范公司机房管理以及网管相关工作。1.2适用范围公司网络机房以及资讯组人员。1.3权责单位(1) 资讯组负责本办法制定、修改、废止之起草工作。(2) 总…

1400小时开源语音数据集,你想要都在这儿

整理 | 一一出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;3 月 1 日&#xff0c;由 Mozilla 基金会发起的 Common Voice 项目&#xff0c;发布新版语音识别数据集&#xff0c;包括来自 42000 名贡献者&#xff0c;超过 1400 小时的语音样本数据&#xff0c;涵盖包括…

【VirtualBox】VirtualBox使用现有的虚拟盘文件(如VHD)创建虚拟机时,报错:打开虚拟硬盘失败,“UUID already exist”的解决方法

###0、问题描述 使用现有的虚拟盘文件&#xff08;如VHD&#xff09;创建虚拟机时&#xff0c;报错&#xff1a;打开虚拟硬盘失败&#xff0c;“UUID already exists”的错误。 ###1、参考博客 https://www.cnblogs.com/xqzt/p/5053338.html https://jingyan.baidu.com/articl…

JDK10 EA版特性速览

今天收到一封邮件组的邮件&#xff0c;是关于JDK 10 First Release Candidate的&#xff0c; JDK10 b43版将作为第一个JDK10的RC版。 b43版特性包括&#xff1a; 286: Local-Variable Type Inference296: Consolidate the JDK Forest into a Single Repository304: Garbage-Col…

linux主机常用管理命令

1.杀掉MYSQL SHELL ps aux|grep mysql|grep -v grep|awk {print $2}|xargs kill -9 2.删除当前目录下0字节的文件 find -type f -size 0 -exec rm -rf {} \; 3.匹配当data里包含"donald"&#xff0c;输出第4列 awk /donald/ {print $4} data 扩展1&#xff1a; awk /…

【Qt】新安装的虚拟机,使用QtCreator第一次编译时报错:g++: Command not found

1、问题描述 新安装的虚拟机&#xff0c;使用QtCreator第一次编译时报错&#xff1a;g: Command not found &#xff08;或着报&#xff0c;make执行失败之类的错误&#xff09; 2、原因分析 新安装的虚拟机中&#xff0c;没有g。一般默认情况是&#xff0c;只安装了gcc 3…

爬一爬那些年你硬盘存过的“老师”

作者 | PayneLi 转载自Python全家桶&#xff08;ID: python-0321&#xff09; 人工智能的现状及今后发展趋势如何&#xff1f; https://edu.csdn.net/topic/ai30?utm_sourcecsdn_bw 最近在Github发现一个基于google浏览器的爬虫项目&#xff0c;此项目是由美国大神2018年开源…

python 打印调用栈

import tracebackdef BBQ():traceback.print_stack() 引入 traceback 包&#xff0c;在某个函数中执行 traceback.print_stack()。 转载于:https://www.cnblogs.com/yourstars/p/8448471.html

(转)修改ETM,用Ogre实现《天龙八部》地形与部分场景详解(附源码)

本文主要讲的是《天龙八部》游戏的地形和一部分场景的具体实现&#xff0c;使用C, Ogre1.6&#xff0c;我摸索了段时间&#xff0c;可能方法用的并不是最好的&#xff0c;但好歹实现了。文章可能讲得有点罗嗦&#xff0c;很多简单的东西都讲了。我是修改了ETM&#xff08;Edita…

【Qt】错误GL/gl.h: No such file or directory的解决方法(以及cannot find -lGL解决方法)

1、问题描述 QtCreator第一次编译时&#xff0c;报错GL/gl.h: No such file or directory 错误信息如下&#xff1a; /home/Qt5.6.3/5.6.3/gcc_64/include/QtGui/qopengl.h:136: error: GL/gl.h: No such file or directory include <GL/gl.h> ^2、原因分析 说明系统里…

java并发之同步辅助类CyclicBarrier和CountDownLatch

CyclicBarrier 的字面意思是可循环使用&#xff08;Cyclic&#xff09;的屏障&#xff08;Barrier&#xff09;。它要做的事情是&#xff0c;让一组线程到达一个屏障&#xff08;也可以叫同步点&#xff09;时被阻塞&#xff0c;直到最后一个线程到达屏障时&#xff0c;屏障才会…

投稿近2000,NAACL 2019接收率仅为22.6%|附录取论文名单

整理 | 若名 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 人工智能的现状及今后发展趋势如何&#xff1f; https://edu.csdn.net/topic/ai30?utm_sourcecsdn_bw 最近真是学术界公布论文产出结果的火热时期&#xff0c;距离计算机视觉领域的顶级盛会 CVPR 2019…

Lucene.Net无障碍学习和使用:索引篇

项目中可能需要再次用到Lucene.Net&#xff0c;利用空闲时间写了个demo&#xff0c;主要涉及到索引的创建、删除、更新和一个简单查询。在本文示例中&#xff0c;Lucene.Net的版本是2.4.0&#xff0c;某些类和方法与最新版本或者较旧的版本有较多不同&#xff0c;希望您阅读顺利…

【ubuntu】vim中鼠标选中时变成 可视模式,不能复制的解决方法

1、问题描述 配置好vim后&#xff0c;打开一个文件&#xff0c;鼠标选中文本时&#xff0c;选中的内容变成可视模式。 可视模式&#xff0c;不能将选中内容复制到剪切板 2、解决方法 在用户根目录下&#xff0c;打开 .vimrc ~$ vi .vimrc 将set mousea 删除或注释掉 3、我的…

Ruby11 拾遗

Agenda LoopExpressionFile Read/WriteDebugProcess & ThreadLoop while a 10 while a > 0puts aa - 1 enduntil a 100until a 0puts aa - 1 endloop a 10loop dobreak if a < 0puts aa - 1 end循环控制 breaknextbreak for x in 1..10break if x 5puts x endne…

CVPR2019|微软、中科大开源基于深度高分辨表示学习的姿态估计算法

作者 | 周强&#xff08;CV君&#xff09; 来源 | 我爱计算机视觉&#xff08;公众号id&#xff1a;aicvml&#xff09; 如何挑战百万年薪的人工智能&#xff01; https://edu.csdn.net/topic/ai30?utm_sourcecsdn_bw 昨天arXiv出现了好几篇被CVPR 2019接收的论文。 其中来自…

本地连接受限制或无法连接怎么办?

一个非常常见的问题&#xff0c;就是我们家用电脑安装宽带后&#xff0c;任务栏上的“本地连接”图标有一个的叹号。查看状态&#xff1a;“受限制或无连接”&#xff0c;点“修复”却无法修复&#xff0c;显示无法获取IP地址&#xff0c;获得私网地址&#xff01;但ADSL又可以…

糟心!苹果无人车裁员190人,程序员却首当其冲

整理 | 琥珀 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 60s测试&#xff1a;你是否适合转型人工智能&#xff1f; https://edu.csdn.net/topic/ai30?utm_sourcecxrs_bw 仅过了一个多月&#xff0c;苹果公司自动驾驶部门裁员的真相便已浮出水面&#xff0c;该…

【工具】Internet Download Manager( IDM )抓取站点

软件说明&#xff1a; 扒网站的好东西&#xff0c;免费&#xff0c;支持中文 下载地址&#xff08;官网&#xff09; http://www.internetdownloadmanager.com/ 使用方法 https://jingyan.baidu.com/article/a681b0de0be10b3b1943465d.html

2010-12-30

I want to invest in stocks to make a quick buck.我想炒股&#xff0c;尽快赚点儿钱花&#xff11;、Which company are you going to invest in?那你打算买什么股&#xff1f;&#xff12;、Dont put all your eggs in one basket造成不要孤注一掷。&#xff13;、You need…

PFLD:简单、快速、超高精度人脸特征点检测算法

作者 | 周强&#xff08;CV君&#xff09; 来源 | 我爱计算机视觉&#xff08;公众号id&#xff1a;aicvml&#xff09; 60s测试&#xff1a;你是否适合转型人工智能&#xff1f; https://edu.csdn.net/topic/ai30?utm_sourcecxrs_bw 什么样的算法才是好算法&#xff1f; 真…

Cookie实现记住密码、自动登录

前端代码 <form id"form" action"xxx" method"post"><div><input type"text" name"account" id"account" placeholder"账号"><input type"text" name"pwd" i…

【Ubuntu】VirtualBox+ubuntu中显示摄像头

1、下载插件 https://www.virtualbox.org/wiki/Downloads 2、修改下载的插件的后缀 将后缀名改为vbox-extpack 如下载的插件为Oracle_VM_VirtualBox_Extension_Pack-5.2.14.txt&#xff0c;改为Oracle_VM_VirtualBox_Extension_Pack-5.2.14.vbox-extpack 3、安装插件 点击…

以SIGSEGV为例详解信号处理(与栈回溯)

以SIGSEGV为例详解信号处理(与栈回溯) 信号是内核提供的向用户态进程发送信息的机制, 常见的有使用SIGUSR1唤醒用户进程执行子程序或发生段错误时使用SIGSEGV保存用户错误现场. 本文以SIGSEGV为例, 详细分析信号使用方法, 内核信号的发送与接收机制. 1. 信号处理例程 以下是一…

十个jQuery图片画廊插件推荐

2019独角兽企业重金招聘Python工程师标准>>> jQuery的画廊插件可以将分组图像和多媒体资料转成类似Flash的图像或照片。当幻灯片已经成为网站的重要组成部分&#xff0c;jQuery的重要性不能被忽视。下面为你介绍了10个最有美感&#xff0c;创新性和创造性的jQuery图…

总结机器学习优质学习文章Top50!

整理 | Jane出品 | AI科技大本营&#xff08;公众号id&#xff1a;rgznai100&#xff09;在过去一年里&#xff0c;我们每个月都会给大家推荐一些优质的、最新的机器学习研究成果或机器学习技术文章&#xff0c;很多文章是从近千篇文章中评选出来的。综合考虑这些文章的更新时间…

【Qt】ubuntu QtCreator的pro文件中使用pkg-config

试验环境 ubuntu14.04.5 opencv2.4.13.6 Qt Creator 4.0.3 Qt 5.6 使用方法 在pro文件中&#xff0c;添加opencv头文件路径 INCLUDEPATH /usr/local/opencv2.4.13.6/include 添加pkg-config –libs opencv CONFIG link_pkgconfig PKGCONFIG opencv 可以在命令行下…

弯曲评论上关于SOC的一段文章【整理】

近几天&#xff0c;弯曲评论上针对一个文章进行了热烈的讨论。这个文章本无关乎SOC&#xff0c;不过&#xff0c;有业界同仁willchen将话题引到了SOC上&#xff0c;并发表了一番言论&#xff0c;整理如下&#xff08;BTW&#xff0c;看着willchen的文字&#xff0c;让我想到了s…

C# richtextbox 自动下拉到最后 方法 RichTextBox读取txt中文后出现乱码

C# richtextbox 自动滚动到最后 光标到最后 自动显示最后一行 private void richTextBox1_TextChanged(object sender, EventArgs e) { richTextBox1.SelectionStart richTextBox1.TextLength; // Scrolls the contents of the control to the current car…

【Qt】在Qt中使用opencv,不要使用opencv创建窗口

问题描述 在ubuntu14.04.5 Qt5.6中使用opencv创建窗口显示摄像头时&#xff0c;报错&#xff1a; (:1103): Gtk-WARNING **: gtk_disable_setlocale() must be called before gtk_init() (:1103): GLib-CRITICAL **: Source ID 52 was not found when attempting to remove …