本文主要讲述我对 iOS 开发的一些理解,希望能通过 app 从启动到退出,将一些的知识整合起来,形成一条知识链,目前涉及到的知识点有 runloop、runtime、文件存储、界面布局、离线推送、内存管理、响应链、多线程。但大部分较为浅显,我尽量写自己的理解,专业性的代码尽量贴上链接,如有不当欢迎指正。

### 1、点击图标,开始上班,开启主线程,开始跑 runloop,

一个 app,启动之后为什么能一直存活并响应用户的操作,就是因为有一个主线程一直存活,并且主线程开启了一个 runloop。关于 runloop 可以粗略的理解为一个 do-while 的死循环,它一遍遍的执行着自己的任务,直到程序进程被杀死才停止。它承担了一个类似于小管家的角色,负责处理定时器的事件、监听用户的操作和处理系统的消息。

更深入一点的理解是,其实 runloop 存在着内核态和用户态两种状态,当没有事件需要处理的时候,就切换为内核态,开始休眠,当接收到事件,就切换为用户态,结束休眠。这样可以避免一般的 while 循环导致的 cpu 忙等待,形成一种“闲”等待,减小 cpu 负担。

runloop 的具体流程如下,需要注意的是:
1、Timers 代表定时器的事件
2、Source0 代表用户触摸事件、和PerformSelectors
3、Source1 代表锁屏/摇晃等系统事件

![runloop](https://upload-images.jianshu.io/upload_images/3288430-7ca2952ad7059140.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

附上YYKit大神的博客地址:[https://blog.ibireme.com/2015/05/18/runloop/](https://blog.ibireme.com/2015/05/18/runloop/)

### 2、主线程开始绘制 UI,开启子线程去本地查询存储的信息,拿到数据后回到主线程刷新界面

这时候,一边开始绘制着欢迎页或者启动页的界面,一边去查询本地有没有存储着登录信息。注意,只能在主线程去绘制 UI,所以查询登录信息是在子线程,这样的好处的是,不阻塞主线程,减少用户的等待时间。

关于多线程的技术,可以理解为一心多用,就像我们可以一边走路一边听歌,我们的大脑在处理走路相关的操作时,也能处理听歌相关的操作。

iOS 里,每一个 app 都有一个自己的小家,我们称为沙盒机制。所有的小家初始样式都是一致的,但内部可以自行装修,增加各种目录结构。

![沙盒目录](https://upload-images.jianshu.io/upload_images/3288430-5fec4ff437cd3fe7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

需要注意的是,每个小家都是单独的,不能走访邻居家做客,即不能访问或修改其他 app 的数据,但可以通过分享的方式,在系统的公证下进行数据交流。部分系统级的资源是公用的,比如相册、摄像头、通讯录等,是类似阳光、空气一样的公用资源。

关于沙盒机制的具体加密原理,大家可以去看下这篇文章[这篇文章](https://blog.csdn.net/youshaoduo/article/details/66478551),嗯,我没看懂。

iOS 里操作本地数据一般有几种方式,按照数据类型可以进行分类,常用的一些零碎信息用偏好设置,大批量的重复数据比如通讯录数据使用数据库,iOS 的数据库是 sqlite,文件类数据直接使用文件写入/读取就可以。

界面绘制的话,是以左上角为坐标原点向右向下延伸的,一个正常的UI控件绘制,一般需要四个元素才能确定坐标,即 X 坐标(横向),Y 坐标(纵向),宽度,高度。也可以使用控件彼此依赖的约束,使用参照原则,原理就是根据设置参照条件获取坐标,比如,控件 A 的宽度等于屏幕宽,控件B的宽度等于控件 A 的宽度,那么就可以计算出控件 B 的宽度为屏幕宽。这种方案总的来说,在性能上是比不上直接设置坐标值,但在屏幕适配上占据很多优势,而且在自动计算控件高度上很轻松,减少了人工计算的步骤,也是目前主流的方案。

![坐标](https://upload-images.jianshu.io/upload_images/3288430-25347d04c8889436.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

### 3、接收到用户输入、点击、滑动等操作,开始处理,

用户的这些操作,是 runloop 捕捉到的,然后根据响应链,一步步的寻找到响应的控件,执行对应的方法。所谓响应链,就是从屏幕开始,倒序遍历所有子控件,如果点击的坐标在该控件的范围内,就返回当前控件,并且继续遍历该控件的子控件,直到找到最小的那个子控件。

这个控件,如果有对应的方法设置,比如点击方法、手势等,那就根据方法,去寻找方法的执行者,寻找的规则是这样,先在当前类的方法列表里寻找,没有就去父类的,再没有就去父类的父类,一直到基类,如果基类也没有,就进入消息转发的流程。

这个消息转发流程的意思就是,系统对开发者说,我一层层的检查完了,都没有响应这个方法的对象,最后给你个机会,要么搞个方法来接替原来的方法,要么就给我个对象去响应这个方法。最后如果走完消息转发流程,还是没法处理,那就崩溃吧。专业的消息转发解析请看[这里](https://www.jianshu.com/p/9263720cbd91)。再深层次的到汇编的解析请看萧玉大神的[这篇文章](http://yulingtianxia.com/blog/2016/06/15/Objective-C-Message-Sending-and-Forwarding/)。

### 4、开始网络请求,等待返回的数据,拿到数据后返回主线程刷新界面,

网络请求一般有 get 和 post 两种请求方式,一般 get 用于不穿参数的拉取数据,如果需要传参数给后台一般使用 post。原因是 get 传参数需要拼接在请求的链接后面,数据的安全得不到保障,而且参数的长度是有限制的,无法传递大量的信息。

关于 http 和 https 大家可以去看[这篇文章](https://juejin.im/post/5dd50eba6fb9a05a6313ebba)。

### 5、重复3、4,间歇性休息放松,自动清理掉不使用的对象,释放内存

iOS 中每个 OC对象,都会有一个 retainCount(引用计数)属性,当对象创建的时候,引用计数都是 1,当其他对象持有这个对象的时候,引用计数加 1,不再持有的时候减 1,对象不再使用的时候再减 1,如果引用计数变为 0,那么这个对象就会立即会被系统回收掉。

后来系统提供了自动释放池的相关接口,原理就是在把对象加入到一个池子里,每次 runloop  将要结束的时候,系统会让这个池子里的所有对象引用计数减 1,如果减 1 后的引用计数为 0,那么就立即回收该对象。注意这里并不存在引用计数变为负数的情况,如果池子里的某个对象在收到系统发送过来的消息之前引用计数已经变为 0,那么该对象立刻就被销毁了,当系统消息到来的时候,该对象已经不存在,即内存地址为空,而向一个空对象做任何操作都是没有反应也没有影响的。

runloop 内部有一个自动释放池,当 runloop 开启时,就会自动创建一个自动释放池,当 runloop 在休息之前会释放掉自动释放池的东西,然后重新创建一个新的空的自动释放池,当 runloop 被唤醒重新开始跑圈时,Timer、Source 等新的事件就会放到新的自动释放池中,当 runloop 退出的时候也会被释放。

说道内存相关,自然就有内存泄漏的相关处理,我之前总结了大部分内存泄漏的情况,具体请看[iOS开发系列之内存泄漏分析(上)](https://www.jianshu.com/p/1b06751130c8)和 [iOS开发系列之内存泄漏分析(下)](https://www.jianshu.com/p/d0008f28053f)。

### 6、午休,进入后台,作为一个进程存在挂起,runloop 休眠,

当用户按下 home 键后,一般 10s 左右 app 就进入了挂起状态,挂起状态的 app 是没有任何活动的。特殊的比如播放音乐、使用定位相关服务、使用 voip(音视频点对点)服务,是可以向系统申请让 app 一直在后台运行的。所以有的公司是采用播放一个无声的音乐来让 app 保持活跃状态,需要注意的是,这种方法会导致上架被拒。

### 7、接收到推送,提醒用户点开 app,休息结束,继续工作,runloop 模式转变,

iOS 的离线推送原理是,由后台对接苹果服务器,app 每次启动后上传自己的设备 token 给后台,当发送需要推送的消息时,由后台找到对应的设备 token,用苹果规定的格式,将消息和 token 一起发给苹果负责推送的服务器 APNs,然后由苹果服务器找到该设备,在系统的层面展示这条推送消息。包括后台 JAVA 代码的全套流程专业解析请看[这里](https://www.cnblogs.com/taintain1984/p/3716642.html)。

另外还有一种推送机制叫做 pushkit,pushkit 区别与普通 APNs 的地方是,它不会弹出通知,而是直接唤醒你的 app,进入回调,也就是说,可以在用户没点击 app 启动的情况下,就运行我们自己写的代码,这样的可操作性就大多了,但由于这种推送会在用户不知情的情况就启动 app,苹果的审核也较为严格。

### 8、

杀掉进程,主线程停止,下班休息。

其实还想加更多的东西进去,不过目前也没好的思路,欢迎评论。

欢迎大家来[我的小窝](https://zmfflying.github.io/)做客啊,里面记录下了我进步的点点滴滴,一切逆境只是前进的理由,与君共勉。

iOS开发系列之app的一天的更多相关文章

  1. iOS开发系列--App扩展开发

    概述 从iOS 8 开始Apple引入了扩展(Extension)用于增强系统应用服务和应用之间的交互.它的出现让自定义键盘.系统分享集成等这些依靠系统服务的开发变成了可能.WWDC 2016上众多更 ...

  2. iOS开发系列--通知与消息机制

    概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情.iOS中通知机制又叫消息机制,其包括两类:一类是本地 ...

  3. iOS开发系列--通知与消息机制--转

    来自:http://www.cocoachina.com/ios/20150318/11364.html 概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户 ...

  4. iOS开发系列--Swift语言

    概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...

  5. iOS开发系列文章(持续更新……)

    iOS开发系列的文章,内容循序渐进,包含C语言.ObjC.iOS开发以及日后要写的游戏开发和Swift编程几部分内容.文章会持续更新,希望大家多多关注,如果文章对你有帮助请点赞支持,多谢! 为了方便大 ...

  6. iOS开发系列--Swift进阶

    概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用S ...

  7. iOS开发系列--数据存取

    概览 在iOS开发中数据存储的方式可以归纳为两类:一类是存储为文件,另一类是存储到数据库.例如前面IOS开发系列-Objective-C之Foundation框架的文章中提到归档.plist文件存储, ...

  8. iOS开发系列--网络开发

    概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...

  9. iOS开发系列--C语言之基础知识

    概览 当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: C语言 OC基础 IOS开发(iphone/ipad) Swift ...

随机推荐

  1. AcWing P165 小猫爬山 题解

    Analysis 这道题是搜索,类似于小木棍,加一些剪枝. 第一个剪枝是如果当前的答案已经大于了我们已知的最小答案,不用说直接return返回即可. 第二个剪枝是我们可以将小猫的体重从大到小排序,这样 ...

  2. Linux操作系统常用命令合集——第四篇-文件系统权限操作(5个命令)

    1.umask [命令作用] 文件或目录创建时的遮罩码 [命令语法] umask     [选项]    [参数] [常用选项] -p  --输出的权限掩码可直接作为指令来执行 -s  --以符号方式 ...

  3. Bzoj 2588 Spoj 10628. Count on a tree(树链剖分LCA+主席树)

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MB Description 给定一棵N个节点的树,每个点 ...

  4. opencv 学习一安装环境vs2015+opencv3

    参考博客 http://www.cnblogs.com/skyfsm/p/6840202.html 针对 模块计算机类型“X64”与目标计算机类型“X86”这个问题,我使用cmake 对环境的工程进行 ...

  5. vue的学习--如何使用Intellij IDEA配置并运行vue项目

    重新接触vue,开始学习使用IDE对vue项目进行配置和运行项目. 1.前面的准备 一般的教程都能到通过命令行运行npm run dev,并通过结果显示的端口,用浏览器访问自己的vue项目的结果.但是 ...

  6. 运维管理SLA

    主要三个概念: SLI 服务关键量化指标,即测试哪些指标,如何测等 SLO :服务等级目标,即要达到哪些目标,如设备正常率3个9.4个9等,即99.9% SLA:  服务等级协议,即如果未完成SLO中 ...

  7. Leetcode题 112 和 113. Path Sum I and II

    112题目如下: Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that addi ...

  8. 8. String to Integer (atoi) ---Leetcode

    Implement atoi to convert a string to an integer. 题目分析: 题目本身很简单就是将一个字符串转化成一个整数,但是由于字符串的千差万别,导致在实现的时候 ...

  9. el-table的type="selection"的使用

    场景:el-table,type="selection"时,重新请求后,设置列表更新前的已勾选项 踩坑:在翻页或者changPageSize之后,table的data会更新,之前勾 ...

  10. element-ui框架的el-dialog弹出框被遮罩层挡住了

    解决办法 在el-dialog标签里添加 :modal-append-to-body='false'