1,LLVM(Low Level Virtual Machine):node
先说说什么是编译器:编译器就是把程序员的代码翻译成机器能够理解的语言的工具。python
再谈谈LLVM:一个模块化和可重用的编译器和工具连接技术的集合,clang是LLVM的子项目,是c,c++,oc编译器,由于多模块的复用,因此提供了惊人的快速编译,比gcc快3倍。其中的 clang static analyzer 主要是进行语法分析,语义分析和生成中间代码,固然这个过程会对代码进行检查,出错的和须要警告的会标注出来。LLVM 核心库提供一个优化器,对流行的 CPU 作代码生成支持。lld 是 Clang / LLVM 的内置连接器,clang 必须调用连接器来产生可执行文件。LLVM 比较有特点的一点是它能提供一种代码编写良好的中间表示 IR,这意味着它能够做为多种语言的后端,这样就可以提供语言无关的优化同时还可以方便的针对多种 CPU 的代码生成。ios
2,LLVM三层结构:c++
第一层:clang编译器,负责编译各类语言;第二层:代码优化器,经过模块化操做优化代码,是bitcode逻辑的主要部分;第三层:代码翻译器,针对不一样平台和GPU将代码翻译成机器语言程序员
3,LLDB:一个有着repl的特性和c++,python插件的开源调试器,LLDB绑定在xcode内部,存在与主窗口底部的控制台中web
4,libc++,libc++ ABI:高性能c++标准库实现,支持c++ 11算法
5,compiler -rt:为LLVM和clang设计的编译器扩展函数库。针对__fixunsdfdi和其余目标机器上没有一个核心IR(intermediate representation)对应的短原生指令序列时,提供高度调优过的底层代码生成支持。编程
6, ABI (Application Binary Interface),中文名:应用二进制接口,是app和操做系统、其余应用之间的二进制接口。它包括如下细节:数据类型的大小、布局和对齐;调用约定(控制着函数的参数如何传送以及如何接受返回值),例如,是全部的参数都经过栈传递仍是部分参数经过寄存器传递,哪一个寄存器用于哪一个函数参数;经过栈传递的第一个函数参数是最早push到栈上仍是最后;系统调用的编码和一个应用如何向操做系统进行系统调用;以及在一个完整的操做系统abi中,目标文件的二进制格式,程序库等等。swift
7,在xcode的project editor中的Build Setting,Build Phases和Build Rules可以控制编译的过程。其中,后端
Build Phases:构建可执行文件的规则,指定target的依赖项目,在target build以前须要先build的依赖,在compile source 中指定全部必须编译的文件,这些文件会根据building setting build rules里的设置来处理。在Link Binary With Libraries里会列出全部的静态库和动态库,它们会和编译生成的目标文件进行连接。build phases 还会把静态资源拷贝到bundle里。还能够经过在build phases里添加自定义脚原本作些事情,好比像 CocoaPods 所作的那样。
Build Rules:指定不一样文件类型如何编译。每条 build rule 指定了该类型如何处理以及输出在哪。能够增长一条新规则对特定文件类型添加处理方法。
Build Settings:在 build 的过程当中各个阶段的选项的设置。
8,静态分析( clang static analyzer):词法->语法->语义->IR->优化->CodeGen
9,IR 总体结构:一个编译的单元即一个文件在 IR 里就是一个 Module,最大的是 Module,里面包含多个 Function,每一个 Function 包含多个 BasicBlock,BasicBlock 里含有 Instruction,代码很是清晰,这样若是想开发一个新语言只须要完成语法解析后经过 LLVM 提供的丰富接口在内存中生成 IR 就能够直接运行在各个不一样的平台。IR 语言知足静态单赋值,能够很好的下降数据流分析和控制流分析的复杂度。及只能在定义时赋值,后面不能更改。可是这样就无法写程序了,输入输出都无法弄,因此函数式编程才会有相似 Monad 这样机制的缘由。
10,dSYM 文件:在每次编译后都会生成一个 dSYM 文件,程序在执行中经过地址来调用方法函数,而 dSYM 文件里存储了函数地址映射,这样调用栈里的地址能够经过 dSYM 这个映射表可以得到具体函数的位置。通常都会用来处理 crash 时获取到的调用栈 .crash 文件将其符号化。能够经过 Xcode 进行符号化,将 .crash 文件,.dSYM 和 .app 文件放到同一个目录下,打开 Xcode 的 Window 菜单下的 organizer,再点击 Device tab,最后选中左边的 Device Logs。选择 import 将 .crash 文件导入就能够看到 crash 的详细 log 了。还能够经过命令行工具 symbolicatecrash 来手动符号化 crash log。一样先将 .crash 文件,.dSYM 和 .app 文件放到同一个目录下,而后输入下面的命令:export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer symbolicatecrash appName.crash appName.app > appName.log
11,Mach-O 文件:记录编译后的可执行文件,对象代码,共享库,动态加载代码和内存转储的文件格式。不一样于 xml 这样的文件,它只是二进制字节流,里面有不一样的包含元信息的数据块,好比字节顺序,cpu 类型,块大小等。文件内容是不能够修改的,由于在 .app 目录中有个 _CodeSignature 的目录,里面包含了程序代码的签名,这个签名的做用就是保证签名后 .app 里的文件,包括资源文件,Mach-O 文件都不可以更改。
Mach-O 文件包含三个区域:
Mach-O Header:包含字节顺序,magic,cpu 类型,加载指令的数量等
Load Commands:包含不少内容的表,包括区域的位置,符号表,动态符号表等。每一个加载指令包含一个元信息,好比指令类型,名称,在二进制中的位置等。
Data:最大的部分,包含了代码,数据,好比符号表,动态符号表等。
12,dyld动态连接:生成可执行文件后就是在启动时进行动态连接了,进行符号和地址的绑定。首先会加载所依赖的 dylibs,修正地址偏移,由于 iOS 会用 ASLR 来作地址偏移避免攻击,肯定 Non-Lazy Pointer 地址进行符号地址绑定,加载全部类,最后执行 load 方法和 clang attribute 的 constructor 修饰函数。
13,dylib 这种格式的表示是动态连接的,编译的时候不会被编译到执行文件中,在程序执行的时候才 link,这样就不用算到包的大小里,并且也可以不更新执行程序就可以更新库。
1,HTTP站在TCP之上:HTTP是创建在TCP协议之上的,TCP协议做为传输层协议其实离应用层并不远。HTTP协议的瓶颈及其优化技巧都是基于tcp协议自己的特性,好比tcp创建连接时三次握手有1.5个RTT (round-trip time)的延迟,为了不每次请求都经历握手带来的延迟,应用层会选择不一样策略的http长连接方案,又好比tcp在创建链接时的初期有慢启动,(slow start)的特性,因此链接的重用总比新建链接性能要好。
2,影响一个网络请求有2个因素:带宽和延迟。随着基础建设的完善,带宽已经有了很大的改善,因此如今延迟就变成了影响网络请求最主要的缘由。
3,客户端是依据域名来向服务器创建链接的,通常pc端浏览器会针对单个域名的server同时创建6-8个链接,而手机端则控制在4-6个,显然链接数并非越多越好,由于链接数越多带来的资源开销和总体延迟都会变大。
4,http1.0的主要面临的问题有2个:第一就是链接没法复用,这样就致使每次请求都会经历三次握手和慢启动,三次握手在高延迟的场景下更明显,若是某次握手过程当中,某一次发生了延迟,这就致使整个过程都会延迟,慢启动则对文件类请求影响较大;第二就是head of line blocking,这个会致使带宽没法充分被利用,以及后续健康请求被阻塞。多个请求一块儿发生时,请求也是一个接着一个进行的,至关于串行队列,后面的须要等到前面的返回了才开始,若是一个有延迟或者不回来,后面的就都有问题了。
5,针对http1.0的链接没法复用的问题,有如下四种方案:(仅app端)
a:基于tcp的长链接,其实就是基于socket的编程,本身制定协议。
b:http long-polling,就是开始就发出链接,可是不立刻返回,等到有新数据才返回,始终有一个链接保持着,返回后用立刻发出新的链接,如此往复。(单向)
c:http streaming,跟b相似,不过初始的streaming不会结束,一直经过这个通道返回数据。(单向)
d:web socket,基于tcp协议,提供双向数据通道,且提供了message的概念,比基于字节流的tcp socket更简单,并且也有长链接功能,不过比较新,有些不支持。
6,head of line blocking:是http2.0以前网络体验的最大祸源,健康的请求会被不健康的请求影响,并且这种体验的损耗受网络环境的影响,出现随机而难以控制。为了解决延迟这个问题,协议的设计者们设计了一种全新的pipelining,可是其实也没有什么卵用,区别把几个请求一次发送过去,不过回来的时候仍是要等的,本质上仍是没有解决问题。
7,致使网络请求延迟的有:tcp初期的slow start,tcp的三次握手,dns查询的延迟等。
8,http2.0是以SPDY为原型进行讨论和标准化的。SPDY基础功能包括:多路复用,请求优先级,header压缩;高级功能包括:server高级推送,server暗示。
9,HTTP2.0针对HTTP1.x的主要改动以下:
1,新的二进制格式:HTTP1.x使用的是明文协议,而HTTP2.0使用的是binary格式
2,链接共享:多路复用,同时还能够设置优先级和依赖
3,header压缩:高效的压缩算法很大的压缩header,减小发送包的数量从而下降延迟
4,HPACK压缩算法的使用
5,重置链接表现更好
6,server push
7,用相似tcp的receive window作流量控制
8,更安全的ssl
10,iOS http现状:iOS系统是从iOS8开始经过NSURLSession来支持SPDY的,iOS9+开始自动支持http2.0;怎么配置最佳的http方案这个因app而异,一是app自己http流量是否大并且密集,二是团队自己的技术条件。http2.0的部署相对容易,客户端开发者甚至不用作什么改动,只须要使用iOS9的sdk编译便可,可是缺点是http2.0只适用于iOS9的设备;SPDY的部署相对麻烦一些,不过能够兼容iOS6+的设备,因此这个具体本身看吧。
1,Snapkit是目前Swift中经过代码进行Auto Layout布局时最流行的开源库。与OC中最主流的Auto Layout开源库Masonry是同一个团队维护,有着类似的API风格。
2,Snapkit因为是swift写的,我之前看过,不过好久没有再看,项目也没有用到,因此这个源码解析我基本没看懂,哈哈。
3,fastlane是一套自动化打包的工具集,用ruby写的,用于ios和Android的自动化打包和发布等工做。
1,在ObjC的初期(2011年以前),CFArray是使用deque双端队列实现的,因此会呈现出头尾操做高效,而中间操做成线性的特色,在容量超过300000左右时,时间复杂度发生陡变。当数据超出阀值的时候,会将数据结构从CFArray转换成CFStorage,CFStorage是一个平衡二叉树结构,为了维护数组的顺序访问,将node的权值使用下标完成插入和旋转操做。不过在2011年之后,CFArray取消了数据结构转换这一功能,或许是为了防止大数据时候二叉树建树的时间抖动问题从而取消的这个特性。其实从它数据结构描述看来,CFArray就是由单一的双端队列进行实现,并且还记录了一些容量信息。
2,C中数组最显著的缺点就是在下标0处插入时,须要移动全部的元素,相似的,当删除第一个元素,在第一个元素前插入一个元素也会形成O(n)复杂度的操做,然而数组是常读写容器,因此O(n)的操做会形成很严重的时间开销。
1,dyld(The Dynamic Link Editor)是苹果的动态连接库,系统内核作好启动程序的初始准备后,将其余事务交给dyld负责。
2,镜像(images)表示的是二进制文件(可执行文件或者动态连接库的.so文件)编译后的符号,代码等。
3,+ load 方法:做为 Objective-C 中的一个方法,与其它方法有很大的不一样。它只是一个在整个文件被加载到运行时,在 main 函数调用以前被 ObjC 运行时调用的钩子方法。关键字有那么几个:文件刚加载,main 函数以前,钩子方法;
4,load 方法是如何被调用的?当 Objective-C 运行时初始化的时候,会经过 dyld_register_image_state_change_handler 在每次有新的镜像加入运行时的时候,进行回调。执行 load_images 将全部包含 load 方法的文件加入列表 loadable_classes ,而后从这个列表中找到对应的 load 方法的实现,调用 load 方法。
5,对于 load 方法的调用顺序有两条规则:父类先于子类调用,类先于分类调用;为何会这样呢,那是由于若是你看过源码你就会发如今把它们添加进能够加载的列表以前就把顺序定好了,好比加进列表的时候会先添加父类再添加子类,先添加类,再添加分类,这样就能确保调用的顺序是正确的。
6,load 的应用:load 能够说咱们在平常开发中能够接触到的调用时间最靠前的方法,在主函数运行以前,load 方法就会调用。因为它的调用不是惰性的,且其只会在程序调用期间调用一次,最最重要的是,若是在类与分类中都实现了 load 方法,它们都会被调用,不像其它的在分类中实现的方法会被覆盖,这就使 load 方法成为了方法调剂(Method swizzling)的绝佳时机。可是因为 load 方法的运行时间过早,因此这里可能不是一个理想的环境,由于某些类可能须要在在其它类以前加载,可是这是咱们没法保证的。不过在这个时间点,全部的 framework 都已经加载到了运行时中,因此调用 framework 中的方法都是安全的。
7,Load 方法做用:load方法是咱们在开发中最接近app启动的可控方法,即在app启动之后,入口函数main以前,因为调用有着non-lazy属性,而且运行期只调用一次,因而咱们可使用load独有的特性和调用时机来尝试Method Swizzling,固然由于load调用时机过早,而且当多个class没有关联(继承与派生),咱们没法知道class中load方法的优先调用关系,因此通常不会在load方法中引入其余的类,这是在开发中要注意的。