本文主要讲述我对 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. Neo4j数据进行备份、还原

    一.neo4j备份方式 neo4j数据库的备份还原分为两种: offline 和 online. Offline backup - dump Dump a database into a single ...

  2. PostgreSQL 学习手册-模式Schema

    一个数据库包含一个或多个命名的模式,模式又包含表.模式还包含其它命名的对象,包括数据类型.函数,以及操作符.同一个对象名可以在不同的模式里使用而不会导致冲突: 比如,schema1和myschema都 ...

  3. [bzoj] Network

    http://www.lydsy.com/JudgeOnline/problem.php?id=3732 /* Kruskal 最小生成树 树链剖分 最大值查询 注意:可能会有几块不联通的图 */ # ...

  4. qt 在windows 以及android 运用资源时的路径使用用限制

    qt中存在以下几种路径的使用方式. 1.qrc内置资源在应用程序中属于只读的资源,作为应用程序的一部分,而不是在一个文件夹中与app分离.资源文件在.qrc文件中的路径如  <file>i ...

  5. ROS文件系统级

    ROS的安装就不介绍了,官方教程是最好的:点击打开链接 ROS是机器人操作系统,它应该有自己的工程结构,Linux系统的文件系统如下: 而ROS的文件系统级如下: 接下来逐一介绍它们: 1. catk ...

  6. Allure自动化测试报告之修改allure测试报告logo

    1.安装allure 2.进入 /usr/local/Cellar/allure/2.10.0/libexec/config 3.在allure.yml添加 - custom-logo-plugin ...

  7. Go By Example-值类型

    Go By Example-值类型 Go语言的数据类型可以分为值类型和引用类型,这里先说值类型. 值类型 值类型:在Go语言中int.float.bool和string这些类型都属于值类型,使用这些类 ...

  8. OpenResty之 limit.count 模块

    原文: lua-resty-limit-traffic/lib/resty/limit/count.md 1. 示例 http { lua_shared_dict my_limit_count_sto ...

  9. AWS 配置IPv6

  10. IDEA导航光标回退和前进快捷键失效

    工作中突然发现IDEA里的Ctrl+Alt+Left/Right失效了,即导航光标的回退和前进,影响看代码的效率. 用Windows Hotkey Explorer查看,发现是被igfxHK.exe进 ...