-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
113 lines (74 loc) · 58.9 KB
/
atom.xml
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>ZTFDeveloper's Blog</title>
<link href="/atom.xml" rel="self"/>
<link href="https://ztfsmart.github.io/"/>
<updated>2017-11-28T10:57:00.513Z</updated>
<id>https://ztfsmart.github.io/</id>
<author>
<name>ZTF</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>shadowsocks服务端配置</title>
<link href="https://ztfsmart.github.io/2017/11/28/shadowsocks%E6%9C%8D%E5%8A%A1%E7%AB%AF%E9%85%8D%E7%BD%AE/"/>
<id>https://ztfsmart.github.io/2017/11/28/shadowsocks服务端配置/</id>
<published>2017-11-28T10:53:41.000Z</published>
<updated>2017-11-28T10:57:00.513Z</updated>
<content type="html"><![CDATA[<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">wget --no-check-certificate -O shadowsocks.sh https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks.sh</div><div class="line">chmod +x shadowsocks.sh</div><div class="line">./shadowsocks.sh 2>&1 | tee shadowsocks.log</div></pre></td></tr></table></figure><a id="more"></a><p>##卸载命令:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">./shadowsocks.sh uninstall</div></pre></td></tr></table></figure></p><p>配置文件路径:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/etc/shadowsocks.json</div></pre></td></tr></table></figure></p><p>##默认配置<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line"> "server":"0.0.0.0",</div><div class="line"> "server_port":8989,</div><div class="line"> "local_address":"127.0.0.1",</div><div class="line"> "local_port":1080,</div><div class="line"> "password":"你的密码",</div><div class="line"> "timeout":300,</div><div class="line"> "method":"aes-256-gcm",</div><div class="line"> "fast_open":false</div><div class="line">}</div></pre></td></tr></table></figure></p><p>server: 服务器ip地址<br>server_port: 绑定的端口,注意不要设置已经使用了的端口<br>possword: 密码<br>timeout: 超时时间<br>method: 加密方法<br>fast_open: 如果你的服务器 Linux 内核在3.7+,可以开启 fast_open 以降低延迟</p><p>##配置多个账号密码<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line">"server":"0.0.0.0",</div><div class="line">"port_password":{</div><div class="line"> "8381":"password1",</div><div class="line"> "8382":"password2",</div><div class="line"> "8383":"password3",</div><div class="line"> "8384":"password4"</div><div class="line"> },</div><div class="line">"timeout":300,</div><div class="line">"method":"aes-256-gcm",</div><div class="line">"fast_open":false</div><div class="line">}</div></pre></td></tr></table></figure></p><p>#启动shadowsocks<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">启动:/etc/init.d/shadowsocks start</div><div class="line">停止:/etc/init.d/shadowsocks stop</div><div class="line">重启:/etc/init.d/shadowsocks restart</div><div class="line">状态:/etc/init.d/shadowsocks status</div></pre></td></tr></table></figure></p><p><a href="http://blog.csdn.net/zhutianfu521" target="_blank" rel="external">更多内容</a></p>]]></content>
<summary type="html">
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">wget --no-check-certificate -O shadowsocks.sh https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks.sh</div><div class="line">chmod +x shadowsocks.sh</div><div class="line">./shadowsocks.sh 2&gt;&amp;1 | tee shadowsocks.log</div></pre></td></tr></table></figure>
</summary>
<category term="随笔" scheme="https://ztfsmart.github.io/tags/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>看<56up>感想</title>
<link href="https://ztfsmart.github.io/2017/11/13/%E7%9C%8B-56up-%E6%84%9F%E6%83%B3/"/>
<id>https://ztfsmart.github.io/2017/11/13/看-56up-感想/</id>
<published>2017-11-13T02:26:32.000Z</published>
<updated>2017-11-13T02:31:10.319Z</updated>
<content type="html"><![CDATA[<p>今天上网看到关于<人生七年>这个记录片的介绍,就特意下载了看看,写下自己的感受</p><p>#生活环境的影响</p><p>感触颇深,上层的孩子,他们从小接触的知识就不同,基本都是看一些金融法律什么的,受的教育也是最好的,但是对于下层的孩子从小想的就是过个小生活,因为他们的圈子就是这个文化.<br>我为什么现在还这么努力的去冲,可能跟我小时候看名人传记的原因,我有自己的理想,有想像他们一样,我想成为他们那样的人,所以从小就要求自己按照他们的生活方式去做,去学习.<br>虽然也走了不少弯路,但是我还是突破了我之前的阶层,已经上升了,也跟中国现在还没有阶级固化有关系.<br>庆幸自己生活在一个有互联网的时代,想改变自己的人生可以通过互联网查到实现的方法,看各种人的人生轨迹,借鉴他们的经验,避免他们的错误.好好规划自己的人生.<br><a id="more"></a></p><p>#阶层改变</p><p>中产阶级的几个人,经过各自的波折最后稳定下来,除了一个有精神问题的,但当他们意识到教育对于孩子的重要性后,让自己的孩子接受良好的教育并有比他们更好的未来.</p><p>底层出身的基本还是各种有问题,除了一个上了牛津学物理的<br>说下我认为这个纪录片中有代表性的一对夫妻,而且他们还是这个记录片的两位<br>出身背景好的女孩和农村上了牛津大学出来的男孩最后走在了一起<br>女的是因为家庭离婚对她影响很大,对生活有反感,而且很叛逆,没有好好的努力<br>男孩因为老师的鼓励,好好学习上了牛津,改变的命运,后来去了美国,成为一个教授<br>女孩是因为家庭的原因和自己的原因导致了自己的阶级下降,但是仍然可以任性的过着中产的生活,知道最后遇到那个通过上学改变命运的男孩,又过上好的生活.<br>这个男孩是让我感同深受的,我也是上学出来的,当时好好学习最基本的动力就是不想在那个小县城继续下去,我要出来见见这个大千世界,通过自己的努力现在在京都过着北漂的生活,还在努力着,也迷茫过,不知道自己值不值得,但是通过这个纪录片,让我意识到,想要改变自己的现状只能通过自己的努力,做到一个让别人无法替代的底部,我没有那么好的家庭背景,也只能算是个中产的家庭,而且下时候还父母离异,跟这母亲长大的,幸亏我姥爷家比较富裕,所以过的还不算差,高考在河北这个高考大省考上了一本,虽然选的专业不好,后来又通过自己转行干了IT,相信以后我也可以通过自己的努力,让自己可以获得别人不能代替的技术或能力,然后积累资源,可以让下一代不至于我这么辛苦.其实视频中很多中产也很努力,但是我觉着努力要对了方向和方法的,富裕的家庭可以给他们正确的方法和途径,所以他们成功比较快,我只能自己去探索,找到好的方向接着努力,有问题了,在寻找方向,经常会迷茫,又经常会有希望,又经常埋头苦干.我觉着寻找途径和方法也是一种能力,就是自学的能力,当有一种掌握一个陌生领域的能力,可以copy到别的所有的领悟.<br>物质满足后的精神世界</p><p>出身比较优越的一个男孩,毕业于牛津大学,金融街工作一年,辞职去做老师,后来去孟买教学,后来又去了教堂….家庭上帝教的这个孩子比较善良,但是没有了私信也就不为自己着想,去非洲支教..孟买支教…被思想控制的一个孩子,人还是要有私欲的,教给孩子现实是什么.他到了42才有女朋友结婚,这个也是家庭教育的失败.但是现在过的还是很富裕的,孩子都是上的特别好的学校</p><p>#规矩</p><p>出身比较好的孩子,从小见识比较广,而且有规矩,有人生规划,上了牛津上了剑桥等好学校,也有个特别好的未来,家庭也很充裕.除了那个家庭离婚,叛逆的女孩.<br>从小家庭给了他们规矩的概念,告诉他们这个社会的规矩,就是学历…..很多时候社会是看学历的(当然也有不太注重的,这里只说大部分),告诉他们这个社会的游戏规则,玩游戏不按照规则来,肯定玩不好,在懂规则的基础上找到漏洞那是另一种能力,暂且不说,就说在懂规矩的的前提下,去根据规则去努力去学习,也就是我上边说到的上升途径,很多规则是我所不知道的,也是在碰壁后才意识到,然后回头又去补充,当然也有一些无法改变的,就比如我的专业是机电,干了IT,人家肯定要怀疑你是不是够专业.这就是社会的规则,它就在那里,制约着你,玩的溜了,就可以如鱼得水,不然就属于逆水行舟,与天斗与地斗,你有那个能力吗.</p><p>#有个个人比较关注的说下</p><p>在底层的人中,那个特别机灵的男孩,后来不至于混的跟那几个女孩一样那么惨,算是底层中过的不错的.他身上有个特别地方,就是不按规矩来,而且特别机灵,过的也不差,但如果他能出身比较好,再加上他这么能混的话,应该会过的更好,这种人可以在懂规则的前提下,去寻找到那个漏洞的人.但只是猜测,随便说说,不要较真.</p><p>#总结下对孩子影响大的地方:<br>1.家庭和睦,不离婚<br>2.给孩子一个稳定的家庭环境<br>3.给孩子好的教育,并引导他好好学习<br>4.通过自己的努力学习获得一个好的社会地位<br>5.教给孩子现实是什么<br>6.教给孩子怎么去谈恋爱<br>7.懂规矩,社会有规则的,而且要了解规则的情况下有自己的见解</p>]]></content>
<summary type="html">
<p>今天上网看到关于&lt;人生七年&gt;这个记录片的介绍,就特意下载了看看,写下自己的感受</p>
<p>#生活环境的影响</p>
<p>感触颇深,上层的孩子,他们从小接触的知识就不同,基本都是看一些金融法律什么的,受的教育也是最好的,但是对于下层的孩子从小想的就是过个小生活,因为他们的圈子就是这个文化.<br>我为什么现在还这么努力的去冲,可能跟我小时候看名人传记的原因,我有自己的理想,有想像他们一样,我想成为他们那样的人,所以从小就要求自己按照他们的生活方式去做,去学习.<br>虽然也走了不少弯路,但是我还是突破了我之前的阶层,已经上升了,也跟中国现在还没有阶级固化有关系.<br>庆幸自己生活在一个有互联网的时代,想改变自己的人生可以通过互联网查到实现的方法,看各种人的人生轨迹,借鉴他们的经验,避免他们的错误.好好规划自己的人生.<br>
</summary>
<category term="随笔" scheme="https://ztfsmart.github.io/tags/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>Objective-C底层数据结构</title>
<link href="https://ztfsmart.github.io/2017/11/09/Object-c%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
<id>https://ztfsmart.github.io/2017/11/09/Object-c底层原理/</id>
<published>2017-11-09T09:10:15.000Z</published>
<updated>2017-11-10T06:47:56.498Z</updated>
<content type="html"><![CDATA[<p>#<strong>Objective-C底层数据结构</strong></p><p>###类的数据结构<br>Class(指针)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">typedef struct objc_class *Class;</div><div class="line"> </div><div class="line">/*</div><div class="line"> 这是由编译器为每个类产生的数据结构,这个结构定义了一个类.这个结构是通过编译器在执行时产生,在运行时发送消息时使用.因此,一些成员改变了类型.编译器产生"char* const"类型的字符串指针替代了下面的成员变量"super_class"</div><div class="line">*/</div><div class="line">struct objc_class {</div><div class="line"> struct objc_class* class_pointer; /* 指向元类的指针. */</div><div class="line"> struct objc_class* super_class; /* 指向父类的指针. 对于NSObject来说是NULL.*/</div><div class="line"> const char* name; /* 类的名称. */</div><div class="line"> long version; /* 未知. */</div><div class="line"> unsigned long info; /* 比特蒙板. 参考下面类的蒙板定义. */</div><div class="line"> long instance_size; /* 类的字节数.包含类的定义和所有父类的定义 */</div><div class="line">#ifdef _WIN64</div><div class="line"> long pad;</div><div class="line">#endif</div><div class="line"> struct objc_ivar_list* ivars; /* 指向类中定义的实例变量的列表结构. NULL代表没有实例变量.不包括父类的变量. */</div><div class="line"> struct objc_method_list* methods; /* 链接类中定义的实例方法. */</div><div class="line"> struct sarray * dtable; /* 指向实例方法分配表. */ </div><div class="line"> struct objc_class* subclass_list; /* 父类列表 */</div><div class="line"> struct objc_class* sibling_class;</div><div class="line"> struct objc_protocol_list *protocols; /* 要实现的原型列表 */</div><div class="line"> void* gc_object_type;</div><div class="line">};</div></pre></td></tr></table></figure><a id="more"></a><p>Method(指针)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">typedef struct objc_method *Method;</div><div class="line"> </div><div class="line">/* 编译器依据类中定义的方法为该类产生一个或更多这种这种结构.</div><div class="line"> 一个类的实现可以分散在一个文件中不同部分,同时类别可以分散在不同的模块中.为了处理这个问题,使用一个单独的方法链表 */</div><div class="line">struct objc_method</div><div class="line">{</div><div class="line"> SEL method_name; /* 这个变量就是方法的名称.编译器使用在这里使用一个`char*`,当一个方法被注册,名称在运行时被使用真正的SEL替代 */</div><div class="line"> const char* method_types; /* 描述方法的参数列表. 在运行时注册选择器时使用.那时候方法名就会包含方法的参数列表.*/</div><div class="line"> IMP method_imp; /* 方法执行时候的地址. */</div><div class="line">};</div></pre></td></tr></table></figure><p>Ivar(指针)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">typedef struct objc_ivar *Ivar;</div><div class="line"> </div><div class="line">/* 编译器依据类中定义的实例变量为该类产生一个或更多这种这种结构 */</div><div class="line">struct objc_ivar</div><div class="line">{</div><div class="line"> const char* ivar_name; /* 类中定义的变量名. */</div><div class="line"> const char* ivar_type; /* 描述变量的类型.调试时非常有用. */</div><div class="line"> int ivar_offset; /* 实例结构的基地址偏移字节 */</div><div class="line">};</div></pre></td></tr></table></figure><p>Category(指针)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">typedef struct objc_category *Category;</div><div class="line"> </div><div class="line">/* 编译器为每个类别产生一个这样的结构.一个类可以具有多个类别同时既包括实例方法,也可以包括类方法*/</div><div class="line">struct objc_category</div><div class="line">{</div><div class="line"> const char* category_name; /* 类别名.定义在类别后面的括号内*/</div><div class="line"> const char* class_name; /* 类名 */</div><div class="line"> struct objc_method_list *instance_methods; /* 链接类中定义的实例方法. NULL表示没有实例方法. */</div><div class="line"> struct objc_method_list *class_methods; /* 链接类中定义的类方法. NULL表示没有类方法. */</div><div class="line"> struct objc_protocol_list *protocols; /* 遵循的协议表 */</div><div class="line">};</div></pre></td></tr></table></figure><p>objc_property_t</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">typedef struct objc_property *objc_property_t;</div></pre></td></tr></table></figure><p>IMP</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">id (*IMP)(id, SEL, ...)</div></pre></td></tr></table></figure><p>SEL</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">typedef struct objc_selector *SEL;</div><div class="line"> </div><div class="line">struct objc_selector</div><div class="line">{</div><div class="line"> void *sel_id;</div><div class="line"> const char *sel_types;</div><div class="line">};</div></pre></td></tr></table></figure><p>objc_method_list<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">struct objc_method_list</div><div class="line">{</div><div class="line"> struct objc_method_list* method_next; /* 这个变量用来链接另一个单独的方法链表 */</div><div class="line"> int method_count; /* 结构中定义的方法数量 */</div><div class="line"> struct objc_method method_list[1]; /* 可变长度的结构 */</div><div class="line">};</div></pre></td></tr></table></figure></p><p>objc_cache</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">struct objc_cache</div><div class="line">{</div><div class="line"> unsigned int mask;</div><div class="line"> unsigned int occupied;</div><div class="line"> Method buckets[1];</div><div class="line">};</div></pre></td></tr></table></figure><p>objc_protocol_list</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">struct objc_protocol_list</div><div class="line">{</div><div class="line"> struct objc_protocol_list *next;</div><div class="line"> size_t count;</div><div class="line"> struct objc_protocol *list[1];</div><div class="line">};</div></pre></td></tr></table></figure><p>###实例的数据结构<br>id</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">typedef struct objc_object *id;</div></pre></td></tr></table></figure><p>objc_object</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">struct objc_object</div><div class="line">{</div><div class="line"> /* 类的指针是对象相关的类.如果是一个类对象, 这个指针指向元类.</div><div class="line"> Class isa;</div><div class="line">};</div></pre></td></tr></table></figure><p>objc_super</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">struct objc_super</div><div class="line">{</div><div class="line"> id self; /* 消息的接受者 */</div><div class="line"> Class super_class; /* 接受者的父类 */</div><div class="line">};</div></pre></td></tr></table></figure><p>#<strong>ios 底层数据结构</strong> </p><p>过去的几年中涌现了大量的Objective-C开发者。有些是从动态语言转过来的,比如Ruby或Python,有些是从强类型语言转过来的,如Java或C#,当然也有直接以Objective-C作为入门语言的。也就是说有很大一部分开发者都没有使用Objective-C太长时间。当你接触一门新语言时,更多地会关注基础知识,如语法和特性等。但通常有一些更高级的,更鲜为人知又有强大功能的特性等待你去开拓。</p><p>这篇文章主要是来领略下Objective-C的运行时(runtime),同时解释是什么让Objective-C如此动态,然后感受下这些动态化的技术细节。希望这回让你对Objective-C和Cocoa是如何运行的有更好的了解。</p><p><strong>The Runtime</strong><br>Objective-C是一门简单的语言,95%是C。只是在语言层面上加了些关键字和语法。真正让Objective-C如此强大的是它的运行时。它很小但却很强大。它的核心是消息分发。</p><p><strong>Messages</strong><br>如果你是从动态语言如Ruby或Python转过来的,可能知道什么是消息,可以直接跳过进入下一节。那些从其他语言转过来的,继续看。</p><p>执行一个方法,有些语言,编译器会执行一些额外的优化和错误检查,因为调用关系很直接也很明显。但对于消息分发来说,就不那么明显了。在发消息前不必知道某个对象是否能够处理消息。你把消息发给它,它可能会处理,也可能转给其他的Object来处理。一个消息不必对应一个方法,一个对象可能实现一个方法来处理多条消息。</p><p>在Objective-C中,消息是通过objc_msgSend()这个runtime方法及相近的方法来实现的。这个方法需要一个target,selector,还有一些参数。理论上来说,编译器只是把消息分发变成objc_msgSend来执行。比如下面这两行代码是等价的。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">[array insertObject:foo atIndex:5];</div><div class="line">objc_msgSend(array, @selector(insertObject:atIndex:), foo, 5);</div></pre></td></tr></table></figure></p><p><strong>Objects, Classes, MetaClasses</strong><br>大多数面向对象的语言里有 classes 和 objects 的概念。Objects通过Classes生成。但是在Objective-C中,classes本身也是objects(译者注:这点跟python很像),也可以处理消息,这也是为什么会有类方法和实例方法。具体来说,Objective-C中的Object是一个结构体(struct),第一个成员是isa,指向自己的class。这是在objc/objc.h中定义的。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">typedef struct objc_object {</div><div class="line"> Class isa;</div><div class="line">} *id;</div></pre></td></tr></table></figure><p>object的class保存了方法列表,还有指向父类的指针。但classes也是objects,也会有isa变量,那么它又指向哪儿呢?这里就引出了第三个类型: metaclasses。一个 metaclass被指向class,class被指向object。它保存了所有实现的方法列表,以及父类的metaclass。如果想更清楚地了解objects,classes以及metaclasses是如何一起工作地,可以阅读这篇文章。</p><p><strong>Methods, Selectors and IMPs</strong><br>我们知道了运行时会发消息给对象。我们也知道一个对象的class保存了方法列表。那么这些消息是如何映射到方法的,这些方法又是如何被执行的呢?</p><p>第一个问题的答案很简单。class的方法列表其实是一个字典,key为selectors,IMPs为value。一个IMP是指向方法在内存中的实现。很重要的一点是,selector和IMP之间的关系是在运行时才决定的,而不是编译时。这样我们就能玩出些花样。</p><p>IMP通常是指向方法的指针,第一个参数是self,类型为id,第二个参数是_cmd,类型为SEL,余下的是方法的参数。这也是self和_cmd被定义的地方。下面演示了Method和IMP</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">- (id)doSomethingWithInt:(int)aInt{}</div><div class="line"> </div><div class="line">id doSomethingWithInt(id self, SEL _cmd, int aInt){}</div></pre></td></tr></table></figure><p>其他运行时的方法<br>现在我们知道了objects,classes,selectors,IMPs以及消息分发,那么运行时到底能做什么呢?主要有两个作用:</p><p>创建、修改、自省classes和objects<br>消息分发<br>之前已经提过消息分发,不过这只是一小部分功能。所有的运行时方法都有特定的前缀。下面是一些有意思的方法:</p><p><strong>class</strong><br>class开头的方法是用来修改和自省classes。方法如class_addIvar, class_addMethod, class_addProperty和class_addProtocol允许重建classes。class_copyIvarList, class_copyMethodList, class_copyProtocolList和class_copyPropertyList能拿到一个class的所有内容。而class_getClassMethod, class_getClassVariable, class_getInstanceMethod, class_getInstanceVariable, class_getMethodImplementation和class_getProperty返回单个内容。</p><p>也有一些通用的自省方法,如class_conformsToProtocol, class_respondsToSelector, class_getSuperclass。最后,你可以使用class_createInstance来创建一个object。</p><p><strong>ivar</strong><br>这些方法能让你得到名字,内存地址和Objective-C type encoding。</p><p><strong>method</strong><br>这些方法主要用来自省,比如method_getName, method_getImplementation, method_getReturnType等等。也有一些修改的方法,包括method_setImplementation和method_exchangeImplementations,这些我们后面会讲到。</p><p><strong>objc</strong><br>一旦拿到了object,你就可以对它做一些自省和修改。你可以get/set ivar, 使用object_copy和object_dispose来copy和free object的内存。最NB的不仅是拿到一个class,而是可以使用object_setClass来改变一个object的class。待会就能看到使用场景。</p><p><strong>property</strong><br>属性保存了很大一部分信息。除了拿到名字,你还可以使用property_getAttributes来发现property的更多信息,如返回值、是否为atomic、getter/setter名字、是否为dynamic、背后使用的ivar名字、是否为弱引用。</p><p><strong>protocol</strong><br>Protocols有点像classes,但是精简版的,运行时的方法是一样的。你可以获取method, property, protocol列表, 检查是否实现了其他的protocol。</p><p><strong>sel</strong><br>最后我们有一些方法可以处理 selectors,比如获取名字,注册一个selector等等。</p><p>现在我们对Objective-C的运行时有了大概的了解,来看看它们能做哪些有趣的事情。</p><p><strong>Classes And Selectors From Strings</strong><br>比较基础的一个动态特性是通过String来生成Classes和Selectors。Cocoa提供了NSClassFromString和NSSelectorFromString方法,使用起来很简单:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Class stringclass = NSClassFromString(@"NSString");</div></pre></td></tr></table></figure><p>于是我们就得到了一个string class。接下来:<br>NSString *myString = [stringclass stringWithString:@”Hello World”];<br>为什么要这么做呢?直接使用Class不是更方便?通常情况下是,但有些场景下这个方法会很有用。首先,可以得知是否存在某个class,NSClassFromString 会返回nil,如果运行时不存在该class的话。比如可以检查NSClassFromString(@”NSRegularExpression”)是否为nil来判断是否为iOS4.0+。</p><p>另一个使用场景是根据不同的输入返回不同的class或method。比如你在解析一些数据,每个数据项都有要解析的字符串以及自身的类型(String,Number,Array)。你可以在一个方法里搞定这些,也可以使用多个方法。其中一个方法是获取type,然后使用if来调用匹配的方法。另一种是根据type来生成一个selector,然后调用之。以下是两种实现方式:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">- (void)parseObject:(id)object {</div><div class="line"> for (id data in object) {</div><div class="line"> if ([[data type] isEqualToString:@"String"]) {</div><div class="line"> [self parseString:[data value]]; </div><div class="line"> } else if ([[data type] isEqualToString:@"Number"]) {</div><div class="line"> [self parseNumber:[data value]];</div><div class="line"> } else if ([[data type] isEqualToString:@"Array"]) {</div><div class="line"> [self parseArray:[data value]];</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div><div class="line">- (void)parseObjectDynamic:(id)object {</div><div class="line"> for (id data in object) {</div><div class="line"> [self performSelector:NSSelectorFromString([NSString stringWithFormat:@"parse%@:", [data type]]) withObject:[data value]];</div><div class="line"> }</div><div class="line">}</div><div class="line">- (void)parseString:(NSString *)aString {}</div><div class="line">- (void)parseNumber:(NSString *)aNumber {}</div><div class="line">- (void)parseArray:(NSString *)aArray {}</div></pre></td></tr></table></figure><p>可一看到,你可以把7行带if的代码变成1行。将来如果有新的类型,只需增加实现方法即可,而不用再去添加新的 else if。</p><p><strong>Method Swizzling</strong><br>之前我们讲过,方法由两个部分组成。Selector相当于一个方法的id;IMP是方法的实现。这样分开的一个便利之处是selector和IMP之间的对应关系可以被改变。比如一个 IMP 可以有多个 selectors 指向它。</p><p>而 Method Swizzling 可以交换两个方法的实现。或许你会问“什么情况下会需要这个呢?”。我们先来看下Objective-C中,两种扩展class的途径。首先是 subclassing。你可以重写某个方法,调用父类的实现,这也意味着你必须使用这个subclass的实例,但如果继承了某个Cocoa class,而Cocoa又返回了原先的class(比如 NSArray)。这种情况下,你会想添加一个方法到NSArray,也就是使用Category。99%的情况下这是OK的,但如果你重写了某个方法,就没有机会再调用原先的实现了。</p><p>Method Swizzling 可以搞定这个问题。你可以重写某个方法而不用继承,同时还可以调用原先的实现。通常的做法是在category中添加一个方法(当然也可以是一个全新的class)。可以通过method_exchangeImplementations这个运行时方法来交换实现。来看一个demo,这个demo演示了如何重写addObject:方法来纪录每一个新添加的对象。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">#import <objc/runtime.h></div><div class="line"> </div><div class="line">@interface NSMutableArray (LoggingAddObject)</div><div class="line">- (void)logAddObject:(id)aObject;</div><div class="line">@end</div><div class="line"> </div><div class="line">@implementation NSMutableArray (LoggingAddObject)</div><div class="line"> </div><div class="line">+ (void)load {</div><div class="line"> Method addobject = class_getInstanceMethod(self, @selector(addObject:));</div><div class="line"> Method logAddobject = class_getInstanceMethod(self, @selector(logAddObject:));</div><div class="line"> method_exchangeImplementations(addObject, logAddObject);</div><div class="line">}</div><div class="line"> </div><div class="line">- (void)logAddObject:(id)aobject {</div><div class="line"> [self logAddObject:aObject];</div><div class="line"> NSLog(@"Added object %@ to array %@", aObject, self);</div><div class="line">}</div><div class="line"> </div><div class="line">@end</div></pre></td></tr></table></figure><p>我们把方法交换放到了load中,这个方法只会被调用一次,而且是运行时载入。如果指向临时用一下,可以放到别的地方。注意到一个很明显的递归调用logAddObject:。这也是Method Swizzling容易把我们搞混的地方,因为我们已经交换了方法的实现,所以其实调用的是addObject:</p><p><strong>动态继承、交换</strong><br>我们可以在运行时创建新的class,这个特性用得不多,但其实它还是很强大的。你能通过它创建新的子类,并添加新的方法。</p><p>但这样的一个子类有什么用呢?别忘了Objective-C的一个关键点:object内部有一个叫做isa的变量指向它的class。这个变量可以被改变,而不需要重新创建。然后就可以添加新的ivar和方法了。可以通过以下命令来修改一个object的class.<br>object_setClass(myObject, [MySubclass class]);<br>这可以用在Key Value Observing。当你开始observing an object时,Cocoa会创建这个object的class的subclass,然后将这个object的isa指向新创建的subclass。点击这里查看更详细的解释。</p><p><strong>动态方法处理</strong><br>目前为止,我们讨论了方法交换,以及已有方法的处理。那么当你发送了一个object无法处理的消息时会发生什么呢?很明显,”it breaks”。大多数情况下确实如此,但Cocoa和runtime也提供了一些应对方法。</p><p>首先是动态方法处理。通常来说,处理一个方法,运行时寻找匹配的selector然后执行之。有时,你只想在运行时才创建某个方法,比如有些信息只有在运行时才能得到。要实现这个效果,你需要重写+resolveInstanceMethod: 和/或 +resolveClassMethod:。如果确实增加了一个方法,记得返回YES。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">+ (BOOL)resolveInstanceMethod:(SEL)aSelector {</div><div class="line"> if (aSelector == @selector(myDynamicMethod)) {</div><div class="line"> class_addMethod(self, aSelector, (IMP)myDynamicIMP, "v@:");</div><div class="line"> return YES;</div><div class="line"> }</div><div class="line"> return [super resolveInstanceMethod:aSelector];</div><div class="line">}</div></pre></td></tr></table></figure><p>那Cocoa在什么场景下会使用这些方法呢?Core Data用得很多。NSManagedObjects有许多在运行时添加的属性用来处理get/set属性和关系。那如果Model在运行时被改变了呢?</p><p><strong>消息转发</strong><br>如果 resolve method 返回NO,运行时就进入下一步骤:消息转发。有两种常见用例。1) 将消息转发到另一个可以处理该消息的object。2) 将多个消息转发到同一个方法。</p><p>消息转发分两步。首先,运行时调用-forwardingTargetForSelector:,如果只是想把消息发送到另一个object,那么就使用这个方法,因为更高效。如果想要修改消息,那么就要使用-forwardInvocation:,运行时将消息打包成NSInvocation,然后返回给你处理。处理完之后,调用invokeWithTarget:。</p><p>Cocoa有几处地方用到了消息转发,主要的两个地方是代理(Proxies)和响应链(Responder Chain)。NSProxy是一个轻量级的class,它的作用就是转发消息到另一个object。如果想要惰性加载object的某个属性会很有用。NSUndoManager也有用到,不过是截取消息,之后再执行,而不是转发到其他的地方。</p><p>响应链是关于Cocoa如何处理与发送事件与行为到对应的对象。比如说,使用Cmd+C执行了copy命令,会发送-copy:到响应链。首先是First Responder,通常是当前的UI。如果没有处理该消息,则转发到下一个-nextResponder。这么一直下去直到找到能够处理该消息的object,或者没有找到,报错。</p><p><strong>使用Block作为Method IMP</strong><br>iOS 4.3带来了很多新的runtime方法。除了对properties和protocols的加强,还带来一组新的以 imp 开头的方法。通常一个 IMP 是一个指向方法实现的指针,头两个参数为 object(self)和selector(_cmd)。iOS 4.0和Mac OS X 10.6 带来了block,imp_implementationWithBlock() 能让我们使用block作为 IMP,下面这个代码片段展示了如何使用block来添加新的方法。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">IMP myIMP = imp_implementationWithBlock(^(id _self, NSString *string) {</div><div class="line"> NSLog(@"Hello %@", string);</div><div class="line">});</div><div class="line">class_addMethod([MYclass class], @selector(sayHello:), myIMP, "v@:@");</div></pre></td></tr></table></figure><p>可以看到,Objective-C 表面看起来挺简单,但还是很灵活的,可以带来很多可能性。动态语言的优势在于在不扩展语言本身的情况下做很多很灵巧的事情。比如Key Value Observing,提供了优雅的API可以与已有的代码无缝结合,而不需要新增语言级别的特性。</p>]]></content>
<summary type="html">
<p>#<strong>Objective-C底层数据结构</strong></p>
<p>###类的数据结构<br>Class(指针)</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">typedef struct objc_class *Class;</div><div class="line"> </div><div class="line">/*</div><div class="line"> 这是由编译器为每个类产生的数据结构,这个结构定义了一个类.这个结构是通过编译器在执行时产生,在运行时发送消息时使用.因此,一些成员改变了类型.编译器产生&quot;char* const&quot;类型的字符串指针替代了下面的成员变量&quot;super_class&quot;</div><div class="line">*/</div><div class="line">struct objc_class &#123;</div><div class="line"> struct objc_class* class_pointer; /* 指向元类的指针. */</div><div class="line"> struct objc_class* super_class; /* 指向父类的指针. 对于NSObject来说是NULL.*/</div><div class="line"> const char* name; /* 类的名称. */</div><div class="line"> long version; /* 未知. */</div><div class="line"> unsigned long info; /* 比特蒙板. 参考下面类的蒙板定义. */</div><div class="line"> long instance_size; /* 类的字节数.包含类的定义和所有父类的定义 */</div><div class="line">#ifdef _WIN64</div><div class="line"> long pad;</div><div class="line">#endif</div><div class="line"> struct objc_ivar_list* ivars; /* 指向类中定义的实例变量的列表结构. NULL代表没有实例变量.不包括父类的变量. */</div><div class="line"> struct objc_method_list* methods; /* 链接类中定义的实例方法. */</div><div class="line"> struct sarray * dtable; /* 指向实例方法分配表. */ </div><div class="line"> struct objc_class* subclass_list; /* 父类列表 */</div><div class="line"> struct objc_class* sibling_class;</div><div class="line"> struct objc_protocol_list *protocols; /* 要实现的原型列表 */</div><div class="line"> void* gc_object_type;</div><div class="line">&#125;;</div></pre></td></tr></table></figure>
</summary>
<category term="iOS" scheme="https://ztfsmart.github.io/tags/iOS/"/>
</entry>
<entry>
<title>我的第一个博客--iPhone X适配</title>
<link href="https://ztfsmart.github.io/2017/11/09/%E6%88%91%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8D%9A%E5%AE%A2/"/>
<id>https://ztfsmart.github.io/2017/11/09/我的第一个博客/</id>
<published>2017-11-09T08:46:40.000Z</published>
<updated>2017-11-10T06:46:35.886Z</updated>
<content type="html"><![CDATA[<p>11月9日更—-八.Home Indicator</p><p>===========================<br>10月25日更—-增加iPhone X需要适配的尺寸的宏定义—六–1</p><p>====================================</p><p>#一.APP在iPhoneX运行后不能占满屏幕,上下都有多余的边</p><blockquote><p>解决方法:把旧的image.xcassets中的LaunchImage删掉,重新创建并在Images.xcassets中为iPhone X添加一个LaunchImage,新的启动图尺寸为1125px × 2436px(375pt × 812pt @3x).</p></blockquote><p><img src="http://img.blog.csdn.net/20170920103636033?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1dGlhbmZ1NTIx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></p><blockquote><p>问题原因:1.应用启动后的显示尺寸会根据启动图的大小来显示,因为旧的工程没有iPhoneX的尺寸,所以就会出现上下有多余边的问题.<br>2.旧工程工程的xcassets没有iPhoneX,所以需要把旧的删掉,重新创建,才可以添加iPhoneX尺寸的启动</p></blockquote><a id="more"></a><p>#二.局部适配</p><p>因为iPhoneX的屏幕上下边角是有弧度的,如果没有适配弧度外是看不到的</p><blockquote><p>iOS11 以前,我们布局时,视图的 top 和 bottom 一般参照的是 Top Layout Guide 和 Bottom Layout Guide<br>iOS11 以后,那两个参照已经 deprecated (过时)了,而被 Safe Area 取代。<br>Safe Area 要求最低支持 iOS9.0<br>最后总结SafeArea</p></blockquote><p>#三.titleview适配<br><img src="http://img.blog.csdn.net/20170921114722128?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1dGlhbmZ1NTIx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>很多APP都会在navigation的titleview上添加搜索框,在iOS11上回出现这种情况的偏移</p><blockquote><p>解决方法:<br>在替换titleview的view里实现方法:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">- (CGSize)intrinsicContentSize {</div><div class="line"> return UILayoutFittingExpandedSize;</div><div class="line">}</div></pre></td></tr></table></figure></p></blockquote><p>#四.适配下拉刷新<br><img src="http://img.blog.csdn.net/20170921115349447?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1dGlhbmZ1NTIx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>下拉在正常状态下会有尺寸偏移</p><blockquote><p>解决方法1:在controller中添加</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">if (@available(iOS 11.0, *)) {</div><div class="line"> self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;</div><div class="line">} else {</div><div class="line"> self.automaticallyAdjustsScrollViewInsets = NO;</div><div class="line">}</div></pre></td></tr></table></figure><blockquote><p>解决方法2:</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">self.automaticallyAdjustsScrollViewInsets = NO;</div><div class="line">self.extendedLayoutIncludesOpaqueBars = YES;</div><div class="line">self.edgesForExtendedLayout = UIRectEdgeTop;</div></pre></td></tr></table></figure><blockquote><p>问题原因:多数情况是在隐藏导航栏出现的,因为iOS11后tableview的automaticallyAdjustsScrollViewInsets属性被废弃了,顶部就多了一定的inset,也可能是SafeArea(安全区域)的原因,关于SafeArea(安全区域)适配下边会写.</p></blockquote><p>如果还是有尺寸偏移那就是tableview的另一个解决方法</p><p>#五.tableview间隙问题</p><blockquote><p>解决方法:实现-tableView: viewForFooterInSection: 和 -tableView: viewForHeaderInSection:方法.或者设置tableview的estimatedRowHeight estimatedSectionHeaderHeight estimatedSectionFooterHeight三个属性为0</p><p>问题原因:iOS 11中如果不实现-tableView: viewForFooterInSection: 和 -tableView: viewForHeaderInSection:,那么-tableView: heightForHeaderInSection:和- tableView: heightForFooterInSection:不会被调用。<br>这是因为在tableview中的 estimatedRowHeight estimatedSectionHeaderHeight estimatedSectionFooterHeight三个高度估算属性由默认的0变成了UITableViewAutomaticDimension,导致高度计算不对。</p><p>#六.SafeArea适配<br><img src="http://img.blog.csdn.net/20170927170324968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1dGlhbmZ1NTIx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"><br>1.官方的安全区域的指导图,旧的项目运行在iPhone X上最大显著的问题就是导航和底部tabbar的位置偏移,因为之前的导航高度为64,随意程序基本都写的死值,适配的话就各种苦逼了,xib和代码的各有各的哭,总之所有的地都要通过判断是否是iPhoneX来适配高度.<br>为了适配我添加了全局的宏<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">//是否是iPhone X</div><div class="line">#define is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)</div><div class="line">//状态栏高度</div><div class="line">#define StatusBarHeight (is_iPhoneX ? 44.f : 20.f)</div><div class="line">// 导航高度</div><div class="line">#define NavigationBarHeight 44.f</div><div class="line">// Tabbar高度. 49 + 34 = 83</div><div class="line">#define TabbarHeight (is_iPhoneX ? 83.f : 49.f)</div><div class="line">// Tabbar安全区域底部间隙</div><div class="line">#define TabbarSafeBottomMargin (is_iPhoneX ? 34.f : 0.f)</div><div class="line">// 状态栏和导航高度</div><div class="line">#define StatusBarAndNavigationBarHeight (is_iPhoneX ? 88.f : 64.f)</div><div class="line"></div><div class="line">#define ViewSafeAreInsets(view) ({UIEdgeInsets insets; if(@available(iOS 11.0, *)) {insets = view.safeAreaInsets;} else {insets = UIEdgeInsetsZero;} insets;})</div></pre></td></tr></table></figure></p></blockquote><p>2.在Storyboard中有SafeArea的选项,但是只支持iOS9以上,你的老板肯定是不会同意的,所以慢慢改吧.</p><p>3.如果使用了Masonry 进行布局,就要适配safeArea<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">if (@available(iOS 11.0, *)) {</div><div class="line"> make.edges.equalTo(self.view.safeAreaInsets);</div><div class="line">} else {</div><div class="line"> make.edges.equalTo(self.view);</div><div class="line">}</div></pre></td></tr></table></figure></p><p>4.在没有适配的页面底部是到屏幕低的,需要设置到安全区域内,把底部的黑条留出来.<br>比如天猫的适配:<br><img src="http://img.blog.csdn.net/20170927174123935?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1dGlhbmZ1NTIx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p><p>#七.UIImagePickerController 设置导航背景图</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[self.navigationBar setBackgroundImage:[UIImage imageNamed:@"navBg"] forBarMetrics:UIBarMetricsDefault];</div></pre></td></tr></table></figure><p>这样设置发现对 UIImagePickerController 不起作用,需要使用:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">self.navigationBar.barTintColor = [UIColor blackColor];</div></pre></td></tr></table></figure></p><p>#八.Home Indicator<br>Home indicator 的设置类似于 prefersStatusBarStyle,iOS 11 增加了 UIViewController 的一个 UIHomeIndicatorAutoHidden 分类来控制 home 键的自动隐藏。通常在全屏播放视频,全屏游戏等场景下会需要用到此特性。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">@interface UIViewController (UIHomeIndicatorAutoHidden)</div><div class="line"></div><div class="line">// Override to return a child view controller or nil. If non-nil, that view controller's home indicator auto-hiding will be used. If nil, self is used. Whenever the return value changes, -setNeedsHomeIndicatorAutoHiddenUpdate should be called.</div><div class="line">- (nullable UIViewController *)childViewControllerForHomeIndicatorAutoHidden API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(watchos, tvos);</div><div class="line"></div><div class="line">// Controls the application's preferred home indicator auto-hiding when this view controller is shown.</div><div class="line">- (BOOL)prefersHomeIndicatorAutoHidden API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(watchos, tvos);</div><div class="line"></div><div class="line">// This should be called whenever the return values for the view controller's home indicator auto-hiding have changed.</div><div class="line">- (void)setNeedsUpdateOfHomeIndicatorAutoHidden API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(watchos, tvos);</div><div class="line"></div><div class="line">@end</div></pre></td></tr></table></figure><p>苹果并没有提供可以手动改变 home indicator 颜色的接口给开发者。因为苹果并不希望我们手动更改 home indicator 的颜色,而应该遵循其自动切换颜色的特性(Home indicator 会根据底色的不同自动切换黑色或白色)。</p><p><a href="https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/" target="_blank" rel="external">官方适配指南</a></p>]]></content>
<summary type="html">
<p>11月9日更—-八.Home Indicator</p>
<p>===========================<br>10月25日更—-增加iPhone X需要适配的尺寸的宏定义—六–1</p>
<p>====================================</p>
<p>#一.APP在iPhoneX运行后不能占满屏幕,上下都有多余的边</p>
<blockquote>
<p>解决方法:把旧的image.xcassets中的LaunchImage删掉,重新创建并在Images.xcassets中为iPhone X添加一个LaunchImage,新的启动图尺寸为1125px × 2436px(375pt × 812pt @3x).</p>
</blockquote>
<p><img src="http://img.blog.csdn.net/20170920103636033?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1dGlhbmZ1NTIx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></p>
<blockquote>
<p>问题原因:1.应用启动后的显示尺寸会根据启动图的大小来显示,因为旧的工程没有iPhoneX的尺寸,所以就会出现上下有多余边的问题.<br>2.旧工程工程的xcassets没有iPhoneX,所以需要把旧的删掉,重新创建,才可以添加iPhoneX尺寸的启动</p>
</blockquote>
</summary>
<category term="随笔" scheme="https://ztfsmart.github.io/tags/%E9%9A%8F%E7%AC%94/"/>
</entry>
</feed>