iOS多线程:『GCD』详尽总结
转自https://www.jianshu.com/p/2d57c72016c6 本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法。这大概是史上最详细、清晰的关于 GCD 的详细讲解+总结的文章了。通过本文,您将了解到: GCD 简介 GCD 任务和队列 GCD 的使用步骤 GCD 的基本使用(6种不同组合区别) GCD 线程间的通信 GCD 的其他方法(栅栏方法:dispatch_barrier_async、延时执行方法:dispatch_after、一次性代码(只执行一次):dispatch_once、快速迭代方法:dispatch_apply、队列组:dispatch_group、信号量:dispatch_semaphore) 1. GCD 简介 什么是 GCD 呢?我们先来看看百度百科的解释简单了解下概念 引自百度百科 Grand Central Dispatch(GCD)...
数字证书原理
转自http://www.360doc.com/content/13/0809/14/1073512_305848184.shtml 1. 基础知识 1.1 公约密码体制 公约密码体制分为三个部分、公钥、私钥加密解密算法,它的加密解密过程如下: 加密:通过加密算法和公钥对内容(或者说明文)进行加密,得到密文。加密过程需要用到公钥。 解密:通过解密算法和私钥对密文进行解密,得到明文。解密过程需要用到的解密算法和私钥。注意,有公钥加密的内容,只能有私钥进行解密,也就是说,有公钥加密的内容,如果不知道私钥是无法解密的。 公钥密码体制的公钥和算法都是公开的(这是为什么叫公钥密码体制的原因),私钥是保密的。大家都可以使用公钥进行加密,但只有私钥的持有者才能解密 1.2、对称加密算法(symmetric key algorithms) 在对称加密算法中,加密使用的密钥和解密使用的密钥是相同的。也就是说,加密和解密都是使用的同一个密钥。因此对称加密算法要保证安全性的话,密钥要做好保密,只能让使用的人知道,不能对外公开。这个和上面的公钥密码体制有所不同,公钥密码体制中加密是用公钥,解密使用私钥,而对称加密算法中,加密和解密都是使用同一个密钥,不区分公钥和私钥。 密钥,一般就是一个字符串或数字,在加密或者解密时传递给加密/解密算法。前面在公钥密码体制中说到的公钥、私钥就是密钥,公钥是加密使用的密钥,私钥是解密使用的密钥。 1.3、非对称加密算法(asymmetric key algorithms) 在非对称加密算法中,加密使用的密钥和解密使用的密钥是不相同的。前面所说的公钥密码体制就是一种非对称加密算法,他的公钥和是私钥是不能相同的,也就是说加密使用的密钥和解密使用的密钥不同,因此它是一个非对称加密算法。 1.4、RSA简介 RSA是一种公钥密码体制,现在使用得很广泛。如果对RSA本身有兴趣的,后面看我有没有时间写个RSA的具体介绍。 RSA密码体制是一种公钥密码体制,公钥公开,私钥保密,它的加密解密算法是公开的。 由公钥加密的内容可以并且只能由私钥进行解密,并且由私钥加密的内容可以并且只能由公钥进行解密。也就是说,RSA的这一对公钥、私钥都可以用来加密和解密,并且一方加密的内容可以由并且只能由对方进行解密。 1.5、签名和加密 我们说加密,是指对某个内容加密,加密后的内容还可以通过解密进行还原。 比如我们把一封邮件进行加密,加密后的内容在网络上进行传输,接收者在收到后,通过解密可以还原邮件的真实内容。 这里主要解释一下签名,签名就是在信息的后面再加上一段内容,可以证明信息没有被修改过,怎么样可以达到这个效果呢?一般是对信息做一个hash计算得到一个hash值,注意,这个过程是不可逆的,也就是说无法通过hash值得出原来的信息内容。在把信息发送出去时,把这个hash值加密后做为一个签名和信息一起发出去。 接收方在收到信息后,会重新计算信息的hash值,并和信息所附带的hash值(解密后)进行对比,如果一致,就说明信息的内容没有被修改过,因为这里hash计算可以保证不同的内容一定会得到不同的hash值,所以只要内容一被修改,根据信息内容计算的hash值就会变化。当然,不怀好意的人也可以修改信息内容的同时也修改hash值,从而让它们可以相匹配,为了防止这种情况,hash值一般都会加密后(也就是签名)再和信息一起发送,以保证这个hash值不被修改。至于如何让别人可以解密这个签名,这个过程涉及到数字证书等概念,我们后面在说到数字证书时再详细说明,这里您先只需先理解签名的这个概念。 2、一个加密通信过程的演化 我们来看一个例子,现在假设“服务器”和“客户”要在网络上通信,并且他们打算使用RSA(参看前面的RSA简介)来对通信进行加密以保证谈话内容的安全。由于是使用RSA这种公钥密码体制,“服务器”需要对外发布公钥(算法不需要公布,RSA的算法大家都知道),自己留着私钥。“客户”通过某些途径拿到了“服务器”发布的公钥,客户并不知道私钥。“客户”具体是通过什么途径获取公钥的,我们后面再来说明,下面看一下双方如何进行保密的通信: 2.1...
RAC怎么处理冷信号与热信号
转自https://tech.meituan.com/talk-about-reactivecocoas-cold-signal-and-hot-signal-part-3.html 第一篇文章中我们介绍了冷信号与热信号的概念,前一篇文章我们也讨论了为什么要区分冷信号与热信号,下面我会先为大家揭晓热信号的本质,再给出冷信号转换成热信号的方法。 揭示热信号的本质 在ReactiveCocoa中,究竟什么才是热信号呢?冷信号是比较常见的,map一下就会得到一个冷信号。但在RAC中,好像并没有“hot signal”这个单独的说法。原来在RAC的世界中,所有的热信号都属于一个类——RACSubject。接下来我们来看看究竟它为什么这么“神奇”。 在RAC2.5文档的框架概述中,有着这样一段描述: A subject, represented by the RACSubject class, is a signal that can be manually controlled. Subjects can be thought of as the “mutable” variant...
为什么要区分冷热信号(二)
转自https://tech.meituan.com/talk-about-reactivecocoas-cold-signal-and-hot-signal-part-2.html 前一篇文章我们介绍了冷信号与热信号的概念,可能有同学会问了,为什么RAC要搞得如此复杂呢,只用一种信号不就行了么?要解释这个问题,需要绕一些圈子。 前面可能比较难懂,如果不能很好理解,请仔细阅读相关文档。 最前面提到了RAC是一套基于Cocoa的FRP框架,那就来说说FRP吧。FRP的全称是Functional Reactive Programming,中文译作函数式响应式编程,是RP(Reactive Programm,响应式编程)的FP(Functional Programming,函数式编程)实现。说起来很拗口。太多的细节不多讨论,我们着重关注下FRP的FP特征。 FP有个很重要的概念是和我们的主题相关的,那就是纯函数。 纯函数就是返回值只由输入值决定、而且没有可见副作用的函数或者表达式。这和数学中的函数是一样的,比如: f(x) = 5x + 1 这个函数在调用的过程中除了返回值以外的没有任何对外界的影响,除了入参x以外也不受任何其他外界因素的影响。 那么副作用都有哪些呢?我来列举以下几个情况: 函数的处理过程中,修改了外部的变量,例如全局变量。一个特殊点的例子,就是如果把OC的一个方法看做一个函数,所有的成员变量的赋值都是对外部变量的修改。是的,从FP的角度看OOP是充满副作用的。 函数的处理过程中,触发了一些额外的动作,例如发送了一个全局的Notification,在console里面输出了一行信息,保存了文件,触发了网络,更新了屏幕等。 函数的处理过程中,受到外部变量的影响,例如全局变量,方法里面用到的成员变量。注意block中捕获的外部变量也算副作用。 函数的处理过程中,受到线程锁的影响算副作用。 由此我们可以看出,在目前的iOS编程中,我们是很难摆脱副作用的。甚至可以这么说,我们iOS编程的目的其实就是产生各种副作用。(基于用户触摸的外界因素,最终反馈到网络变化和屏幕变化上。) 接下来我们来分析副作用与冷热信号的关系。既然iOS编程中少不了副作用,那么RAC在实际的使用中也不可避免地要接触副作用。下面通过一个业务场景,来看看冷信号中副作用的坑: self.sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://api.xxxx.com"]]; self.sessionManager.requestSerializer...
冷信号与热信号
转自https://tech.meituan.com/talk-about-reactivecocoas-cold-signal-and-hot-signal-part-1.html 背景 ReactiveCocoa(简称RAC)是最初由GitHub团队开发的一套基于Cocoa的FRP框架。FRP即Functional Reactive Programming(函数式响应式编程),其优点是用随时间改变的函数表示用户输入,这样就不需要可变状态了。我们之前的文章“RACSignal的Subscription深入分析”里曾经详细讲解过RAC核心概念之一RACSignal的实现原理。在美团客户端中,我们大量使用了这个框架。冷信号与热信号的概念很容易混淆并造成一定的问题。鉴于这个问题具有一定普遍性,我将用一系列文章讲解RAC中冷信号与热信号的相关知识点,希望可以加深大家的理解。本文是系列文章的第一篇。 p.s. 以下代码和示例基于ReactiveCocoa v2.5。 什么是冷信号与热信号 冷热信号的概念源于.NET框架Reactive Extensions(RX)中的Hot Observable和Cold Observable,两者的区别是: Hot Observable是主动的,尽管你并没有订阅事件,但是它会时刻推送,就像鼠标移动;而Cold Observable是被动的,只有当你订阅的时候,它才会发布消息。 Hot Observable可以有多个订阅者,是一对多,集合可以与订阅者共享信息;而Cold Observable只能一对一,当有不同的订阅者,消息是重新完整发送。 这里面的Observables可以理解为RACSignal。为了加深理解,我们来看这样的几组代码: RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@1];...
RAC初探
转自https://tech.meituan.com/RACSignalSubscription.html 本文主要包含2个部分,前半部分主要分析RACSignal的subscription过程,后半部分是对前半部分的深入,在subscription过程的基础上分析ReactiveCocoa中比较难理解的两个操作:multicast && replay。 PS:为了解释清楚,我们下面只讨论next,不讨论error以及completed,这二者与next类似。本文基于ReactiveCocoa 2.x版本。 我们先刨析RACSignal的subscription过程 RACSignal的常见用法 -(RACSignal *)signInSignal { //part 1:[RACSignal createSignal]来获得signal return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [self.signInService signInWithUsername:self.usernameTextField.text password:self.passwordTextField.text complete:^(BOOL success) { // part 3: 进入didSubscribe,通过[subscriber...
线程和进程
进程(process) 狭义的定义:进程就是一段程序的执行过程。 广义定义:进程是一个具有一定独立功能的程序关于某次数据集合的一次运行活动,它是操作系统分配资源的基本单元。 简单来讲进程的概念主要有两点:第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程中调用的指令和本地变量。第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。 进程状态:进程有三个状态,就绪,运行和阻塞。就绪状态其实就是获取了除cpu外的所有资源,只要处理器分配资源马上就可以运行。运行态就是获取了处理器分配的资源,程序开始执行,阻塞态,当程序条件不够时,需要等待条件满足时候才能执行,如等待I/O操作的时候,此刻的状态就叫阻塞态。 说说程序,程序是指令和数据的有序集合,其本身没有任何运动的含义,是一个静态的概念,而进程则是在处理机上的一次执行过程,它是一个动态的概念。进程是包含程序的,进程的执行离不开程序,进程中的文本区域就是代码区,也就是程序。 线程(thread) 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。 多线程(multiThread) 在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。 最简单的比喻多线程就像火车的每一节车厢,而进程则是火车。车厢离开火车是无法跑动的,同理火车也不可能只有一节车厢。多线程的出现就是为了提高效率。 ###说说区别 进程与线程的区别: 进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。 简而言之,一个程序至少有一个进程,一个进程至少有一个线程. 线程的划分尺度小于进程,使得多线程程序的并发性高。 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。 说说优缺点 线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP(多核处理机)机器上运行,而进程则可以跨机器迁移。
使用LLDB进行调试
1.LLDB LLDB是LLVM中可重用组建构建的下一代高性能调试器,包括完整的LLVM编译器,其中就有LLVM的Clang表达式解析器和反汇编程序。对我们开发人员拉说意味着LLDB能理解你的编译器所能理解的语法。 2.使用LLDB进行调试 使用LLDB进行调试跟GDB的差别微乎其微,了解LLDB内部的工作机制及带来的细微差异,能让你成为更好的开发人员。 ###2.1 dSYM文件 调试信息文件(dsYM)中存储着与目标有关的调试信息。调试器通常集成在开发环境中,开发环境中通常支持放置断点使应用停止运行,从而查看代码中变量的值,有两种调试器:机器语言调试器能够运行到断电时显示逆向过来的汇编代码,允许你观察寄存器中的值,汇编人员通常使用这种调试器。符号调试器能够在调试代码时显示应用中使用的符号或变量,跟机器语言调试器不同,符号调试器语序你查看代码中的符号,而不是寄存器中和内存地址。 让符号调试器工作起来,需要一个编译过的代码和你编写源代码之间的链接或者映射,这正是调试信息文件中所包含的内容。调试器能够参考调试信息文件,根据你在源代码中放置的断点让应用程序停在正确的位置。Xcode的调试信息文件被称作为dSYM文件(因为文件扩展名为.dsYM)。 ###2.2 符号化 LLVM在内的编译器都是用来将源代码转为汇编代码的。所有汇编代码都有一个基地址,你定义的变量,用到的堆和栈都依赖这个基地址。每次运行时,这个基地址都会变。符号化使用方法名和变量名来替换基地址的过程,基地址是应用的入口地址,可以符号化其他符号,方法就是计算它们相对于基地址的偏移,然后将他们映射到dSYM文件中。符号化的过程在用Xcode调试应用进行,或者用Instruments做性能分析时进行。 Xcode的符号化 我们快速的看一下Xcode创建的xcarchive包,它里面包含如下目录:dSYMs、Products以及一个Info.plist文件,dSYMs目录含有工程中包含的目标/静态库对应的所有dSYM文件。Products目录含有所有的可执行二进制文件。Info.plist与工程中的plist文件相同,当你将从iTunesConnect中得到的.crash文件拖到Xcode中时,Xcode内部会查找归档文件,找出与崩溃报告匹配的info.plist文件,然后从哪个归档文件的dYSMs目录获取.dYSM文件。这就是不能删除已提交归档文件的原因。如果在应用提交之后就删除了这些归档文件,那么当你尝试对一个崩溃报告进行符号化时,很有可能陷入困境。 将dSYM提交到版本控制系统中 另一个存储dSYM的方法是将他们提交到版本控制系统中,这样在我们拿到崩溃报告时,可以检验跟提交的版本对应的dSYM,并通过匹配崩溃报告和dSYM对崩溃报告进行符号化。这样团队中所有的开发人员都能够访问dSYM文件,而对崩溃调试则可以有任何团队成员来完成。 ###2.3 断点导航面板 可以使用Cmd + 6来快速访问断点导航面板,支持为异常和符号设置断点 异常断点 在代码有问题导致跑出异常时,异常断点会终止程序的执行,Foundation.framework的NSArray,UIKit类中的一些方法会在不满足特定条件下抛出异常。例如数组越界,UitableView会在会在行数声明为“n”,而没有为每行提供单元格时抛出异常。调试异常在理论上比较容易,但理解造成异常的源相当复杂。应用在崩溃时只会在日志中显示造成崩溃的那条异常,但Foundation.framework方法会在整个工程中都用到,不撤职断点,即时看了日志也不知道发生了什么,设置了断点后,调试器会在异常抛出的瞬间暂停程序的执行,但在捕获异常之前,你需要在断点导航面板中查看崩溃了的那个线程的站轨迹。 符号断点 符号断点会在执行到特定符号时暂停程序。符号可以是一个方法名,类中的一个方法或者任何c方法(obj_msgSend)。 malloc_error_break和 -[NSObject doesNotRecognizeSelector]对调试跟内存相关的崩溃很有帮助,如果应用崩溃了并抛出EXC_BAD_ACCESS,那么在其中一个或全部两个符号上设置断点能狗帮助你定位问题。 编辑断点 开发者创建的每个断点都可以在导航面板中修改。按住Ctrl并点击断点,然后在菜单中选择Edit Breakpoint的方式来编辑断点。你会看到一个断点编辑页,通常断点会在每次执行到该行时停止程勋的执行,你可以编辑断点设置一个条件,从而创建一个条件断点,只有在满足条件时,该断点才会执行。...
Git的指令学习
1.新建一个本地仓库 $git init 2.配置仓库 告诉git你是谁 git config user.name xxx 告诉git怎么联系你 git config user.email xxxx 全局配置 $ git config --global user.name xxx $ git config --global user.name xxx 如何学习git指令 学习git 指令和svn指令是一样的,只不过展现的方式不一样,git...