0%

证书、私钥和CA

现在我们所说的证书一般是指服务器证书,也就是公钥加上域名、公司信息、序列号、签名信息等组成;

私钥和公钥相对应,私钥加密的东西只能公钥解密,公钥加密的东西只能私钥解密,并且不能由公钥推断出私钥,但是可以由私钥算出公钥来。所以这里有一件非常有意思的事情,你可以在公私钥不变的情况下换一张证书,因为证书其实包括其他信息,所以你换的是别的信息,这些信息的变化会导致证书签名也会变化,所以就变成了一张新的证书,但是公钥私钥是没有变化的。

CA也由证书和私钥组成,它的证书和普通的证书长得差不多,只是其中的Basic Constraint字段里面的CA值为True而已,普通的服务器证书这一块为False,但是因为有了这个True,所以CA可以签发别的证书。
服务器证书的分类

可以从两个维度去看证书的分类,一种是商业角度,为了区分不同的用户级别,服务端证书可以分成DV、OV和EV证书。

Read more »

导语

本文的目的,一是简要分析下对服务器身份验证的完整握手过程,二是证书链的验证,三是探索下iOS中原生库NSURLConnection或NSURLSession如何支持实现https。

Read more »

基本技巧

标题

1
2
3
4
5
6
7
8
9
10
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题
标题1
======
标题2
------

粗斜体

1
2
3
*斜体文本*    _斜体文本_
**粗体文本** __粗体文本__
***粗斜体文本*** ___粗斜体文本___

链接

1
2
文字链接[链接名称](http://链接网址)
网址链接

高级链接技巧

1
2
3
4
5
6
链接 1 作为网址变量 [Google][1].
链接 yahoo 作为网址变量 [Yahoo!][yahoo].
然后在文档的结尾为变量赋值(网址)

[1]\: http://www.google.com/
[yahoo]\: http://www.yahoo.com/

列表 - 普通 - 无序 - 列表

1
2
3
\- 列表文本前使用 [减号+空格]
\+ 列表文本前使用 [加号+空格]
\* 列表文本前使用 [星号+空格]
  • 普通
  • 有序
  • 列表
  1. 列表前使用 [数字+空格]
  2. 我们会自动帮你添加数字
  3. 不用担心数字不对,显示的时候我们会自动把这行的 7 纠正为 3

列表嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1. 列出所有元素:
- 无序列表元素 A
1. 元素 A 的有序子列表
- 前面加四个空格
2. 列表里的多段换行:
前面必须加四个空格,
这样换行,整体的格式不会乱
3. 列表里引用:

> 前面空一行
> 仍然需要在 > 前面加四个空格

4. 列表里代码段:


1
前面四个空格,之后按代码语法 ``` 书写


或者直接空八个,引入代码块

引用 > 普通引用

1
2
3
4
5
6
7
8
9
10
> 引用文本前使用 [大于号+空格]
> 折行可以不加,新起一行都要加上哦
> 引用里 > > 嵌套引用
> 最外层引用
> > 多一个 > 嵌套一层引用
> > > 可以嵌套很多层
> - 引用里嵌套列表
> - 这是引用里嵌套的一个列表
> - 还可以有子列表
> * 子列表需要从 - 之后延后四个空格开始

图片

跟链接的方法区别在于前面加了个感叹号 !,这样是不是觉得好记多了呢?

1
![图片名称](http://图片网址)

当然,你也可以像网址那样对图片网址使用变量

链接 1 作为网址变量 [Google][1]. 然后在文档的结尾位变量赋值(网址)

也可以使用 HTML 的图片语法来自定义图片的宽高大小

1
2
3
<code>
`<image src="http://7xt737.com1.z0.clouddn.com/blog_image14384920.jpg" width="100">`
</code>

换行

如果另起一行,只需在当前行结尾加 2 个空格

1
2
3
在当前行的结尾加 2 个空格  
这行就会新起一行
如果是要起一个新段落,只需要空出一行即可。

分隔符

如果你有写分割线的习惯,可以新起一行输入三个减号-。当前后都有段落时,请空出一行:

1
2
3
4
5
6
7
<pre>
前面的段落

---

后面的段落
</pre>

高级技巧

行内 HTML 元素

目前只支持部分段内 HTML 元素效果,包括
<kdb> <b> <i> <em> <sup> <sub> <br>

键位显示

使用

<kbd>Ctrl<kbd>+<kbd>Alt<kbd>+<kbd>Del<kbd> shi重启电脑

代码块

使用 (`
`) 元素同样可以形成代码块

粗斜体

<b> Markdown 在此处同样适用,如 <b>加粗<b> == 加粗

符号转义

如果你的描述中需要用到 markdown 的符号,比如 _ # * 等,但又不想它被转义,这时候可以在这些符号前加反斜杠,如 \_ \# \* 进行避免。

_不想这里的文本变斜体_

**不想这里的文本被加粗**

扩展

支持 jsfiddle、gist、runjs、优酷视频,直接填写 url,在其之后会自动添加预览点击会展开相关内容。

1
2
3
4
http://{url_of_the_fiddle}/embedded/[{tabs}/[{style}]]/
https://gist.github.com/{gist_id}
http://runjs.cn/detail/{id}
http://v.youku.com/v_show/id_{video_id}.html

公式

当你需要在编辑器中插入数学公式时,可以使用两个美元符 $$ 包裹 TeX 或 LaTeX 格式的数学公式来实现。提交后,问答和文章页会根据需要加载 Mathjax 对数学公式进行渲染。如:

``
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a}. $$

$$ x \href{why-equal.html}{=} y^2 + 1 $$
``

同时也支持 HTML 属性,如:

``
$$ (x+1)^2 = \class{hidden}{(x+1)(x+1)} $$

$$ `(x+1)^2 = \cssId{step1}{\style{visibility:hidden}{(x+1)(x+1)}} $$
``

表格

1
2
3
4
| 一个普通标题 | 一个普通标题 | 一个普通标题 |
| ------| ------ | ------ |
| 短文本 | 中等文本 | 稍微长一点的文本 |
| 稍微长一点的文本 | 短文本 | 中等文本 |
一个普通标题 一个普通标题 一个普通标题
短文本 中等文本 稍微长一点的文本
稍微长一点的文本 短文本 中等文本

update 2017.1.9

update 2017.7.24 markdowm 格式优化

导致卡顿的操作

CPU 消耗型任务

布局计算

布局计算是 iOS 中最为常见的消耗 CPU 资源的地方,如果视图层级关系比较复杂,计算出所有图层的布局信息就会消耗一部分时间。因此我们应该尽量提前计算好布局信息,然后在合适的时机调整对应的属性。还要避免不必要的更新,只在真正发生了布局改变时再更新。
对象创建

对象创建过程伴随着内存分配、属性设置、甚至还有读取文件等操作,比较消耗 CPU 资源。尽量用轻量的对象代替重量的对象,可以对性能有所优化。比如 CALayer 比 UIView 要轻量许多,如果视图元素不需要响应触摸事件,用 CALayer 会更加合适。

通过 Storyboard 创建视图对象还会涉及到文件反序列化操作,其资源消耗会比直接通过代码创建对象要大非常多,在性能敏感的界面里,Storyboard 并不是一个好的技术选择。

对于列表类型的页面,还可以参考 UITableView 的复用机制。每次要初始化 View 对象时先根据 identifier 从缓存池里取,能取到就复用这个 View 对象,取不到再真正执行初始化过程。滑动屏幕时,会将滑出屏幕外的 View 对象根据 identifier 放入缓存池,新进入屏幕可见范围内的 View 又根据前面的规则来决定是否要真正初始化。

Autolayout

Autolayout 是苹果在 iOS6 之后新引入的布局技术,在大多数情况下这一技术都能大大提升开发速度,特别是在需要处理多语言时。比如阿拉伯语下布局是从右往左,通过 Autolayout 设置 leading 和 trailing 即可。
但是 Autolayout 对于复杂视图来说常常会产生严重的性能问题,对于性能敏感的页面建议还是使用手动布局的方式,并控制好刷新频率,做到真正需要调整布局时再重新布局。

文本计算

如果一个界面中包含大量文本(比如微博、微信朋友圈等),文本的宽高计算会占用很大一部分资源,并且不可避免。
一个比较常见的场景是在 UITableView 中,heightForRowAtIndexPath这个方法会被频繁调用,即使不是耗时的计算在调用次数多了之后也会带来性能损耗。这里的优化就是尽量避免每次都重新进行文本的行高计算,可以在获取到 Model 数据后就根据文本内容计算好布局信息,然后将这份布局信息作为一个属性保存到对应的 Model 中,这样在 UITableView 的回调中就可以直接使用 Model 中的属性,减少了文本的计算。

文本渲染

屏幕上能看到的所有文本内容控件,包括 UIWebView,在底层都是通过 CoreText 排版、绘制为 Bitmap 显示的。常见的文本控件 (UILabel、UITextView 等),其排版和绘制都是在主线程进行的,当显示大量文本时,CPU 的压力会非常大。
这一部分的性能优化就需要我们放弃使用系统提供的上层控件转而直接使用 CoreText 进行排版控制。
Wherever possible, try to avoid making changes to the frame of a view that contains text, because it will cause the text to be redrawn. For example, if you need to display a static block of text in the corner of a layer that frequently changes size, put the text in a sublayer instead.
上面这段话引用自 iOS Core Animation: Advanced Techniques,翻译过来的意思就是说包含文本的视图在改变布局时会触发文本的重新渲染,对于静态文本我们应该尽量减少它所在视图的布局修改。

图像的绘制

图像的绘制通常是指用那些以 CG 开头的方法把图像绘制到画布中,然后从画布创建图片并显示的过程。调用 CG 开头的方法消耗的是 CPU 资源。我们可以将绘制过程放到后台线程,然后在主线程里将结果设置到 layer 的 contents 中。代码如下:

1
2
3
4
5
6
7
8
9
10
11
- (void)display {
dispatch_async(backgroundQueue, ^{
CGContextRef ctx = CGBitmapContextCreate(...);
// draw in context...
CGImageRef img = CGBitmapContextCreateImage(ctx);
CFRelease(ctx);
dispatch_async(mainQueue, ^{
layer.contents = img;
});
});
}

图片的解码

1
Once an image file has been loaded, it must then be decompressed. This decompression can be a computationally complex task and take considerable time. The decompressed image will also use substantially more memory than the original.

图片被加载后需要解码,图片的解码是一个复杂耗时的过程,并且需要占用比原始图片还多的内存资源。

为了节省内存,iOS 系统会延迟解码过程, 在图片被设置到 layer 的 contents 属性或者设置成 UIImageView 的 image 属性后才会执行解码过程,但是这两个操作都是在主线程进行,还是会带来性能问题。

如果想要提前解码,可以使用 ImageIO 或者提前将图片绘制到 CGContext 中,这部分实践可以参考 iOS Core Animation: Advanced Techniques

这里多提一点,常用的 UIImage 加载方法有 imageNamedimageWithContentsOfFile。其中 imageNamed 加载图片后会马上解码,并且系统会将解码后的图片缓存起来,但是这个缓存策略是不公开的,我们无法知道图片什么时候会被释放。因此在一些性能敏感的页面,我们还可以用 static 变量 hold 住 imageNamed 加载到的图片避免被释放掉,以空间换时间的方式来提高性能。

GPU消耗型任务

相对于 CPU 来说,GPU 能干的事情比较单一:接收提交的纹理(Texture)和顶点描述(三角形),应用变换(transform)、混合并渲染,然后输出到屏幕上。宽泛的说,大多数 CALayer 的属性都是用 GPU 来绘制。
以下一些操作会降低 GPU 绘制的性能,

大量几何结构

所有的 Bitmap,包括图片、文本、栅格化的内容,最终都要由内存提交到显存,绑定为 GPU Texture。不论是提交到显存的过程,还是 GPU 调整和渲染 Texture 的过程,都要消耗不少 GPU 资源。当在较短时间显示大量图片时(比如 TableView 存在非常多的图片并且快速滑动时),CPU 占用率很低,GPU 占用非常高,界面仍然会掉帧。避免这种情况的方法只能是尽量减少在短时间内大量图片的显示,尽可能将多张图片合成为一张进行显示。

另外当图片过大,超过 GPU 的最大纹理尺寸时,图片需要先由 CPU 进行预处理,这对 CPU 和 GPU 都会带来额外的资源消耗。
视图的混合

当多个视图(或者说 CALayer)重叠在一起显示时,GPU 会首先把他们混合到一起。如果视图结构过于复杂,混合的过程也会消耗很多 GPU 资源。为了减轻这种情况的 GPU 消耗,应用应当尽量减少视图数量和层次,并且减少不必要的透明视图。

离屏渲染

离屏渲染是指图层在被显示之前是在当前屏幕缓冲区以外开辟的一个缓冲区进行渲染操作。

离屏渲染需要多次切换上下文环境:先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上又需要将上下文环境从离屏切换到当前屏幕,而上下文环境的切换是一项高开销的动作。

会造成 offscreen rendering 的原因有:

  • 阴影(UIView.layer.shadowOffset/shadowRadius/…)
  • 圆角(当 UIView.layer.cornerRadius 和 UIView.layer.maskToBounds 一起使用时)
  • 图层蒙板
  • 开启光栅化(shouldRasterize = true)

使用阴影时同时设置 shadowPath 就能避免离屏渲染大大提升性能。

CALayer 有一个 shouldRasterize 属性,将这个属性设置成 true 后就开启了光栅化。开启光栅化后会将图层绘制到一个屏幕外的图像,然后这个图像将会被缓存起来并绘制到实际图层的 contents 和子图层,对于有很多的子图层或者有复杂的效果应用,这样做就会比重绘所有事务的所有帧来更加高效。但是光栅化原始图像需要时间,而且会消耗额外的内存。

光栅化也会带来一定的性能损耗,是否要开启就要根据实际的使用场景了,图层内容频繁变化时不建议使用。最好还是用 Instruments 比对开启前后的 FPS 来看是否起到了优化效果。

自定义 IOS TextView,高度自增自减

如何实现UITextView文本框高度随文字行数自动增减呢?

思路1、UITextView的Delegate方法

-textViewDidChange:

在Text变化时计算文字高度,刷新TextView高度

问题:

Text变化与实际有出入,此时的问题变化还没有存储到TextView的Text中,现在进行计算会得到上一个状态下的文字高度,导致TextView高度刷新延迟,换行第二个文字才增加高度,如果采用这个方法,就要进行文字拼接,再计算文字高度。

实现:不够优雅,不实现。

思路2、TextView本质是一个ScrollView

文字高度超出TextView高度会自动增加contentSize属性的height,而且增加的高度刚好就是TextView需要改变的高度,不错。

实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//宽度、高度与坐标

\#define Main_Screen_Height [[UIScreen mainScreen] bounds].size.height
\#define Main_Screen_Width [[UIScreen mainScreen] bounds].size.width
static float TextViewDefaultHeight = 30.;
static float TextViewDefaultY = 5.;
static float TextViewContentSizeDefaultHeight = 22.;
//测试中使用[UIFont systemFontOfSize:14],每行高度变化为17
self.TextViewInput = [[UITextView alloc]initWithFrame:CGRectMake(45, UUInputTextViewDefaultY, Main_Screen_Width, UUInputTextViewDefaultHeight)];
[self.TextViewInput setContentSize:CGSizeMake(self.TextViewInput.width, UUInputTextViewContentSizeDefaultHeight)];
self.TextViewInput.delegate = self;
self.TextViewInput.font = [UIFont systemFontOfSize:14];
self.TextViewInput.textContainerInset = UIEdgeInsetsMake(6,0, 0, 0);
//KVO监听TextViewInput的contentSize变化
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.TextViewInput addObserver:self forKeyPath:@"contentSize" options:options context:nil];
[self addSubview:self.TextViewInput];
\#pragma mark -- KVO --
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"contentSize"]){
//最高行数设置,本demo中最高四行,对应paste场景
if (self.TextViewInput.height > UUInputTextViewDefaultHeight+17*2 && self.TextViewInput.contentSize.height > UUInputTextViewContentSizeDefaultHeight+17*2) {
return;
}
//文本为空时处理,对应文字发送、cut场景
if (self.TextViewInput.text.length == 0) {
[UIView animateWithDuration:0.3 animations:^{
self.TextViewInput.frame = CGRectMake(45, UUInputTextViewDefaultY, Main_Screen_Width-2*45, UUInputTextViewDefaultHeight);
} completion:nil];
return;
}
CGRect frame = self.TextViewInput.frame;
//高度变化值
float changeHeight = self.TextViewInput.contentSize.height - UUInputTextViewContentSizeDefaultHeight;
//超过限定高度的场景处理
if (changeHeight > 17*2) {
changeHeight = 17*2;
}
frame.origin.y = UUInputTextViewDefaultY - changeHeight;
frame.size.height = UUInputTextViewDefaultHeight + changeHeight;
//动画效果
[UIView animateWithDuration:0.3 animations:^{
self.TextViewInput.frame = frame;
} completion:nil];
NSLog(@"%lf-- TextViewInput",self.TextViewInput.contentSize.height);
}
}
//注意要注销KVO

-(void)dealloc{
[self.TextViewInput removeObserver:self forKeyPath:@"contentSize"];
}

如何实现UITextView文本框高度随文字行数自动增减呢?

思路1、UITextView的Delegate方法

-textViewDidChange:

在Text变化时计算文字高度,刷新TextView高度

问题:Text变化与实际有出入,此时的问题变化还没有存储到TextView的Text中,现在进行计算会得到上一个状态下的文字高度,导致TextView高度刷新延迟,换行第二个文字才增加高度,如果采用这个方法,就要进行文字拼接,再计算文字高度。

思路2、TextView本质是一个ScrollView

文字高度超出TextView高度会自动增加contentSize属性的height,而且增加的高度刚好就是TextView需要改变的高度

Read more »

事到用时方恨少,想来还是记录下来靠谱;

开始写博客大概是2013年,那时候是在CSDN上写写博客,不过那时候还在上大学,更新文章基本看心情,而且大多文章也不过是转载看到的一些技术博客,原创记录基本很少;现在回头看来那时就是浮躁,肚子里没点墨水却硬要去写,矫情啦!

现在,大学毕业,会想过去四年的确发生了很多事情,有些事情很有趣、有些事情很悲伤,但还有很多事情已经没什么印象;

现在建立个人博客,想记录下生活感想,想分享下技术心得,一点点的记录,用时间和文字来见证自己吧。

学习、工作中经常遇到一些问题,向别人询问时,应当注意不要问“太蠢的问题”。

“蠢”,不是指问题的需要的智商度数,而是自己是否了解这个问题,是否已经通过一些常用的方法去尝试过了?如果能用搜索引擎解决的问题,你硬要让别人给你解答,那么谁都不会欢迎这种蠢问题吧。

问题,其实可可以进行多次分隔:如想实现什么?想如何实现?能如何实现?

Read more »