RunLoop
runloop是一个事件循环对象。
do {
//接受消息->等待->处理
}while(message != quit)
- 概念:事件循环对象,在循环过程中处理各种事件(点击、刷新等),从而保持程序持续运行;在没有事件处理的时候,会进入睡眠模式,从而节省CPU资源,提高程序性能。
- 为什么需要:一个线程只能执行一个任务,执行完就会退出,如果我们需要一种机制,让线程能随时处理时间但并不退出,那么 RunLoop 就是这样的一个机制。Runloop是事件接收和分发机制的一个实现。
- Runloop 和线程是绑定在一起的。每个线程(包括主线程)都有一个对应的 Runloop 对象。我们并不能自己创建 Runloop 对象,但是可以获取到系统提供的 Runloop 对象。
是否接触TableView渲染性能相关的东西?
cell的数目,配置tableview数据
重用单元格的形式,数据成千上万行,最终渲染个数为屏幕上显示的数目。
往下拉的时候,最上面的cell到最下面来,放置重复渲染,提高手机性能。
刷新页面的两种方法
- 无动画效果:tableView.reloadData(),就是相当于执行 cell for row的方法,将结果取出来,再更新视图
- 将刷新语句放在View.beginUpdates()、tableView.endUpdates()中间,可以提高app的性能
事件处理
触摸屏幕、晃动设备、通过遥控设施控制设备。对应的事件类型有以下三种:
- 触屏事件(Touch Event)
- 运动事件(Motion Event)
- 远端控制事件(Remote-Control Event)
响应者链
当发生事件响应时,必须知道由谁来响应事件。在 iOS 中,由响应者链来对事件进行响应。
所有事件响应的类都是 UIResponder 的子类,响应者链是一个由不同对象组成的层次结构,其中的每个对象将依次获得响应事件消息的机会。
1 | First Responser --> The Window --> The Application --> nil(丢弃) |
我们可以通过 [responder nextResponder]
找到当前 responder 的下一个 responder,持续这个过程到最后会找到 UIApplication 对象。
通常情况下,我们在 First Responder (一般也就是用户当前触控的 View )这里就会响应请求,进入下面的事件分发机制。
事件分发
第一响应者(First responder)指的是当前接受触摸的响应者对象(通常是一个 UIView 对象),即表示当前该对象正在与用户交互,它是响应者链的开端。响应者链和事件分发的使命都是找出第一响应者。
- iOS 系统检测到手指触摸 (Touch) 操作时会将其打包成一个 UIEvent 对象,并放入当前活动 Application 的事件队列,
- 单例的 UIApplication 会从事件队列中取出触摸事件并传递给单例的 UIWindow 来处理,
- UIWindow 对象首先会使用
hitTest:withEvent:
方法寻找此次 Touch 操作初始点所在的视图(View),即需要将触摸事件传递给其处理的视图,这个过程称之为 hit-test view。
内存管理机制:ARC自动引用计数\MRC
创建的时候为1,使用的时候+1,不需要的时候-1,为0的时候系统知道其不需要了,则release。
class和struct
相同点
- 可以定义存储属性
- 能够定义方法
- 通过下标操作访问实例所包含的值
- 通过扩展来增加默认实现功能
不同点
- 类可以继承
- 类型转换允许在运行时检查和解释一个类实例的类型
- 析构器允许一个类实例释放任何它所被分配的资源
- 引用计数允许一个类的多次引用
- class是引用类型,struct是值类型
- struct会自动生成一个初始化所有属性的构造器
多线程
谈及 iOS 中的多线程,一般说的是 pthread,NSthread,GCD,NSOperation 这四种, 用的最多也最方便的就是 GCD 了。
四、线程安全问题
当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。就好比几个人在同一时修改同一个表格,造成数据的错乱。
解决多线程安全问题的方法
- 方法一:互斥锁(同步锁)
1 | `@synchronized(锁对象) {`` ``// 需要锁定的代码``}` |
加了互斥做的代码,当新线程访问时,如果发现其他线程正在执行锁定的代码,新线程就会进入休眠。
- 方法二:自旋锁
加了自旋锁,当新线程访问代码时,如果发现有其他线程正在锁定代码,新线程会用死循环的方式,一直等待锁定的代码执行完成。相当于不停尝试执行代码,比较消耗性能。
GCD 中两个重要重要概念 —— 队列 & 任务
队列是一种特殊的线性表,采用FIFO(先进先出)的原则,队列的主要作用是用来存放任务。
GCD会自动将队列中的任务取出,放到对应的线程中执行。
串行队列(Serial Dispatch Queue): 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务
并发队列(Concurrent Dispatch Queue): 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务), 并发功能只有在异步(dispatch_async)函数下才有效
队列执行任务的方式:
- 同步:在当前线程中执行,当前代码不执行完,就不能够执行下一条代码。会阻塞当前线程。
异步:在另一条线程中执行(不用等待当前代码执行完,就能够执行下一条),不会阻塞当前线程。
主队列 (串行)
1 | let mainQueue = DispatchQueue.main |
- 全局队列 (并发)
1 | let globalQueue = DispatchQueue.global() |
全局队列默认是并发队列,在不进行第三方框架或者大型的商业应用开发,全局队列基本够用。
- 主队列
dispatch_main_queue();
串行 ,更新UI - 全局队列
dispatch_global_queue();
并行,四个优先级:background
,low
,default
,high
- 自定义队列
dispatch_queue_t queue;
可以自定义是并行:DISPATCH_QUEUE_CONCURRENT
或者串行DISPATCH_QUEUE_SERIAL
同步不开异步开,串行开1条,并行开多条。
队列中的任务同步执行,队列就不具有开启线程的能力, 队列中的任务异步执行,队列就具有开启线程的能力。
(同步和异步执行决定的是否有开启线程的能力)
如果队列具 有开启线程的能力 (队列任务异步执行) 且队列是 串行队列 ,那么将会 开启 1 条线程 。
如果队列具 有开启线程的能力 (队列任务异步执行) 且队列是 并发队列 ,那么将会 开启 多 条线程 。开启线程的条数由 GCD 决定。
2.1 全局队列
全局队列是获取的,不是程序员创建的。
为了方便 GCD 的使用,apple 默认为我们提供的。
全局队列默认是并发队列,在不是进行第三方框架或者大型的商业应用开发,全局队列基本够用。
全局 ( 并发 ) 队列异步执行 :
并发队列异步(不阻塞当前线程)执行(队列就具有开启线程的能力), 队列会开启多条线程。
1 | 任务异步执行不会阻塞当前线程, |
1 | func async() { |
全局 ( 并发 ) 队列同步执行 :
并发队列同步(阻塞当前线程)执行(队列就不具有开启线程的能力), 队列不会开启线程(代码都在主线程中执行)。
1 | 任务同步执行会阻塞当前线程, |
1 | func sync() { |
2.2 主队列
主队列是获取的,不是程序员创建的,apple 默认为我们提供的。
(app 开发中,所有的 UI 更新操作都应该在主线程中进行)
主队列(串行)异步执行
主队列异步(不会阻塞当前线程)执行(队列就具有开启线程的能力), 队列会开启线程(开启的线程就是主线程)。
1 | > 有朋友问我,异步会开启线程, 主队列异步就不会开启线程。 |
主队列异步的操作主要用在更新 UI 操作中。 具体参考 项目开发中 GCD 代码使用。
1 | func async() { |
主队列(串行)同步执行
执行的效果就俩字 死锁
主线程同步,在 Swift 中,编译阶段就报错,在 oc 中是在运行的时候才能发现。体现的主要是界面的 “假死”。
UITableView
要实现Tableview必须要签订2个协议
UITableViewDelegate:数据视图的普通协议,作用是:处理数据视图事件.
UITableViewDataSource:数据视图的数据代理协议,作用是:处理视图的数据代理.
实现签订的协议的2个协议方法:
返回数字,每个section有多少个row
返回cell,cell就是TableView显示时候的格子内容,根据indexPath和数据决定;
观察者设计模式、KVO
设计模式——观察者设计模式
A对B的变化感兴趣,就注册为B的观察者,当B发生变化时通知A,告知B发生了变化。
指定一个被观察对象(例如 A 类),当对象某个属性(例如 A 中的字符串 name)发生更改时,对象会获得通知,并作出相应处理;
在 MVC 设计架构下的项目,KVO 机制很适合实现 mode 模型和 view 视图之间的通讯。比如label中的对象为 num=0 ,我们按下按钮之后对象的num++,则label改变。
设计模式——通知机制
当用户从后台进入,从非活跃的状态进入活跃状态的时候,系统自动发送“becomeActive”通知,如果有注册监听者(观察者),则执行回调方法。【天气预报需要用】
网络
浏览器进行一次网络请求都需要哪些步骤?
- 1、域名解析:
- 浏览器查找域名的 IP 地址、
- 没找到后发送给 DNS 服务器(本地host,电信),让它解析为 IP 地址
- 2、TCP的三次握手
- 3、建立TCP连接后发起HTTP请求,浏览器向 web 服务器发送一个 HTTP 请求
- HTTP请求格式:是请求方法(GET/POST/DELETE/PUT/HEAD)、URI路径、HTTP版本号。
- 3. 2 服务器响应HTTP请求:状态行、响应头、空行、消息体。
- 4、浏览器解析html代码,并请求html代码中的资源
- 服务器的永久重定向响应:“https://www.google.com/” 而非“http://google.com/”。
三次握手
第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接。