-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
417 lines (362 loc) · 80.7 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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>R0R0N0A's blog</title>
<link href="/atom.xml" rel="self"/>
<link href="http://roron0a.github.io/"/>
<updated>2017-05-18T03:30:17.000Z</updated>
<id>http://roron0a.github.io/</id>
<author>
<name>R0R0N0a</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Jerkins-Xcode集成自动化部署-AutomaticCI-With-Jerkins</title>
<link href="http://roron0a.github.io/2017/05/18/Jerkins-Xcode%E9%9B%86%E6%88%90%E8%87%AA%E5%8A%A8%E5%8C%96%E9%83%A8%E7%BD%B2-AutomaticCI-With-Jerkins/"/>
<id>http://roron0a.github.io/2017/05/18/Jerkins-Xcode集成自动化部署-AutomaticCI-With-Jerkins/</id>
<published>2017-05-17T17:41:34.000Z</published>
<updated>2017-05-18T03:30:17.000Z</updated>
<content type="html"><![CDATA[<p>#引言</p>
<blockquote>
<p>谁会做重复的没有效率的事情呢?</p>
</blockquote>
<p><strong>每次打包然后上传->本地测试/TF</strong><br>真是受够了 浪费生命无异于自杀。<br>谷歌了下能否自动化 果然有。<br>记录下步骤。仅做备份。</p>
<p>#什么是CI</p>
<ul>
<li>持续集成, 简称CI(continuous integration)。</li>
<li>CI作为敏捷开发重要的一步,其目的在于让产品快速迭代的同时,尽可能保持高质量。</li>
<li>CI一种可以增加项目可见性,降低项目失败风险的开发实践。其每一次代码更新,都要通过自动化测试来检测代码和功能的正确性,只有通过自动测试的代码才能进行后续的交付和部署。</li>
<li>CI 是团队成员间(产研测)更好地协调工作,更好的适应敏捷迭代开发,自动完成减少人工干预,保证每个时间点上团队成员提交的代码都能成功集成的,可以很好的用于对Android/iOS项目的打包。</li>
</ul>
<p>#Why CI ?<br><strong>Dont Repeat YOURSELF</strong></p>
<hr>
<p>#Jerkins</p>
<ul>
<li>安装</li>
</ul>
<p><strong>喜闻乐见的<code>homebrew</code></strong></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">brew install jerkins</div></pre></td></tr></table></figure>
<p>然后在<code>iTerm2</code>里输入<code>jerkins</code><br>然后本地访问 就可以看到<code>jerkins</code>的主界面</p>
<ul>
<li><p>插件<br>管理插件里面 就是安装<code>Xcode</code>和 <code>git</code>以及<code>证书</code> <code>签名</code> <code>FTP</code>等相关的插件</p>
</li>
<li><p>创建Job</p>
</li>
</ul>
<p>我创建的是自由风格软件 这其中最主要的就是git的操作以及公钥私钥还有证书了</p>
<ol>
<li>不要下载<strong>历史</strong><code>git</code>版本。</li>
<li>公钥私钥就是<code>~/.ssh</code>里面的了</li>
<li>路径啥的自己选</li>
</ol>
<ul>
<li>打包</li>
</ul>
<p><strong>我个人喜欢用命令行</strong></p>
<ol>
<li><p>Clean</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">xcodebuild clean -project ./YourProject.xcodeproj -configuration Release</div></pre></td></tr></table></figure>
</li>
<li><p>Archive</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">xcodebuild archive -workspace ./YourProject.xcworkspace -scheme YourProject -archivePath </div><div class="line">YourProject.xcarchive CODE_SIGN_IDENTITY="YOUR_CODE_SIGN_IDENTITY" </div><div class="line">PROVISIONING_PROFILE="YOUR_PROVISIONING_PROFILE"</div></pre></td></tr></table></figure>
</li>
<li><p>Export</p>
</li>
</ol>
<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">xcodebuild -exportArchive -archivePath YourProject.xcarchive -exportPath YourProject.ipa </div><div class="line">-exportOptionsPlist exportOptions.plist</div></pre></td></tr></table></figure>
<ul>
<li>安装</li>
</ul>
<p><strong>我个人还是喜欢命令行。</strong></p>
<p><code>iOS-Deploy</code></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">npm i -g ios-deploy</div></pre></td></tr></table></figure>
<p>然后</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">ios-deploy -b yourProject.ipa</div></pre></td></tr></table></figure>
<h1 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h1><p><code>CODE_SIGN_IDENTITY</code> 即证书 <code>Xcode</code>如果配置好就不用找了 或者 在钥匙串里找</p>
<p><code>PROVISIONING_PROFILE</code> 注意 这个不要扩展名</p>
<p><code>exportOptions.plist</code> 这个有格式要求 如下</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"><?xml version="1.0" encoding="UTF-8"?></div><div class="line"><plist version="1.0"></div><div class="line"><dict></div><div class="line"> <key>yourTeamID</key></div><div class="line"> <string>Some</string></div><div class="line"> <key>method</key></div><div class="line"> <string>Some</string></div><div class="line"></dict></div><div class="line"></plist></div></pre></td></tr></table></figure>
<p><code>cocoapods</code>管理的话 <strong>注意</strong><br><code>pod install --verbose --no-repo-update</code> </p>
<p>#后记<br>想到什么再补充 </p>
]]></content>
<summary type="html">
<p>#引言</p>
<blockquote>
<p>谁会做重复的没有效率的事情呢?</p>
</blockquote>
<p><strong>每次打包然后上传-&gt;本地测试/TF</strong><br>真是受够了 浪费生命无异于自杀。<br>谷歌了下能否自动化 果然有。<
</summary>
</entry>
<entry>
<title>iptables的另类用法</title>
<link href="http://roron0a.github.io/2017/05/16/iptables%E7%9A%84%E5%8F%A6%E7%B1%BB%E7%94%A8%E6%B3%95/"/>
<id>http://roron0a.github.io/2017/05/16/iptables的另类用法/</id>
<published>2017-05-15T17:46:08.000Z</published>
<updated>2017-05-15T17:58:31.000Z</updated>
<content type="html"><![CDATA[<p>#引言</p>
<blockquote>
<p>iptables是用来设置、维护和检查Linux内核的IP包过滤规则的,iptables可以定义不同的表,每个表都包含几个内部的链,也能包含用户定义的链。<br>hashlimit是iptables的一个匹配模块,用它结合iptables的其它命令可以实现限速的功能(注意,单独hashlimit模块是无法限速的)。</p>
</blockquote>
<p>首先要知道。这只是个匹配模块<br>如果你用过Surge就知道 这只是一些个规则 符合我们就执行 不符合pass<br>就是基本原理是<strong>匹配–处理</strong><br><code>hashlimit</code>在这个工作过程中只能起到匹配的作用,它本身是<strong>无法对网络数据包进行任何处理的</strong>。</p>
<p>#实例<br><strong>两个步骤:</strong></p>
<ul>
<li><p>对符合hashlimit匹配规则包放行</p>
</li>
<li><p>丢弃/拒绝未放行的包</p>
</li>
</ul>
<p>下面是一个简单的例子:</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">iptables -A INPUT -p tcp --dport 22 -m hashlimit </div><div class="line">--hashlimit-name ssh </div><div class="line">--hashlimit 5/sec </div><div class="line">--hashlimit-burst 10 </div><div class="line">--hashlimit-mode srcip </div><div class="line">--hashlimit-htable-expire 90000 -j ACCEPT </div><div class="line">iptables -A INPUT -p tcp --dport 22 -j DROP</div></pre></td></tr></table></figure>
<p>#然后,我们来着重讲讲hashlimit模块具体是如何工作的。</p>
<p><code>hashlimit</code>的匹配是基于令牌桶 <code>(Token bucket)</code>模型的。令牌桶是一种网络通讯中常见的缓冲区工作原理,它有两个重要的参数,令牌桶容量n和令牌产生速率s。我们可以把令牌当成是门票,而令牌桶则是负责制作和发放门票的管理员,它手里最多有n张令牌。</p>
<p>一开始,管理员开始手里有n张令牌。每当一个数据包到达后,管理员就看看手里是否还有可用的令牌。如果有,就把令牌发给这个数据包,<code>hashlimit</code>就告诉<code>iptables</code>,这个数据包被匹配了。而当管理员把手上所有的令牌都发完了,再来的数据包就拿不到令牌了。这时,<code>hashlimit</code>模块就告诉<code>iptables</code>,这个数据包不能被匹配。除了发放令牌之外,只要令牌桶中的令牌数量少于n,它就会以速率s来产生新的令牌,直到令牌数量到达n为止。通过令牌桶机制,即可以有效的控制单位时间内通过(匹配)的数据包数量,又可以容许短时间内突发的大量数据包的通过(只要数据包数量不超过令牌桶n)。</p>
<p><code>hashlimit</code>模块提供了两个参数–<code>hashlimi</code>t和<code>--hashlimit-burst</code>,分别对应于令牌产生速率和令牌桶容量。除了令牌桶模型外,<code>hashlimit</code>匹配的另外一个重要概念是匹配项。在<code>hashlimit</code>中,每个匹配项拥有一个单独的令牌桶,执行独立的匹配计算。通过<code>hashlimit</code>的–<code>hashlimit-mode</code>参数,你可以指定四种匹配项及其组合,即:srcip(每个源地址IP为一个匹配项),dstip(每个目的地址IP为一个匹配项),srcport(每个源端口为一个匹配项),dstport(每个目的端口为一个匹配项)</p>
<p>除了前面介绍的三个参数外,hashlimit还有一个必须要用的参数,即–hashlimit-name。 hashlimit会在/proc/net/ipt_hashlimit目录中,为每个调用了hashlimit模块的iptables 命令建立一个文件,其中保存着各匹配项的信息。–hashlimit-name参数即用来指定该文件的文件名。</p>
<p>好了,以上我们已经介绍了hashlimit的工作原理和相应的参数,下面我们来看几个例子。</p>
<p>首先是前面的那个例子:</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">iptables -A INPUT -p tcp --dport 22 -m hashlimit </div><div class="line">--hashlimit-name ssh </div><div class="line">--hashlimit 5/sec </div><div class="line">--hashlimit-burst 10 </div><div class="line">--hashlimit-mode srcip </div><div class="line">--hashlimit-htable-expire 90000 -j ACCEPT </div><div class="line">iptables -A INPUT -p tcp --dport 22 -j DROP</div></pre></td></tr></table></figure>
<p>在了解了hashlimit各参数的含义之后,我们现在就可以知道这两条iptables命令的作用。</p>
<ol>
<li><p>为所有访问本机22端口的不同IP建立一个匹配项,匹配项对应的令牌桶容量为10,令牌产生速率为5个每秒。放行通过匹配的数据包。</p>
</li>
<li><p>丢弃所有其它访问本机22端口的数据包。</p>
</li>
</ol>
<p>通过这两条命令,我们就实现了限制其它机器对本机22端口(ssh服务)频繁访问的功能.</p>
<p>再来我们看一个复杂点的限速。假设我们现在在一台NAT网关上,想限制内部网某个网段 192.168.1.2/24对外的访问频率。(这个的主要作用是限制内部中毒主机对外的flood攻击)</p>
<p>那我们可以这么做:</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></pre></td><td class="code"><pre><div class="line">iptables -N DEFLOOD </div><div class="line">iptables -A FORWARD -s 192.168.1.2/24 -m state --state NEW -j DEFLOOD </div><div class="line">iptables -A DEFLOOD -m hashlimit --hashlimit-name deflood --hashlimit 10/sec --hashlimit-burst 10 --hashlimit-mode srcip -j ACCEPT </div><div class="line">iptables -P DEFLOOD -j DROP </div><div class="line">``` </div><div class="line"></div><div class="line">* 命令建立了一个自定义的处理链</div><div class="line"></div><div class="line">* 所有来自192.168.1.2/24网段,并且打算新建网络连接的数据包,都进入DEFLOOD链处理</div><div class="line"></div><div class="line">* 在DEFLOOD链中,为每个IP建立一个匹配项,对应令牌桶容量为10,产生速率为10个每秒。放行通过匹配的数据包。</div><div class="line"></div><div class="line">* 在DEFLOOD链中丢弃所有其它的数据包</div><div class="line"></div><div class="line">当然,hashlimit还有一些其他的参数,比如</div></pre></td></tr></table></figure>
<p>–hashlimit-htable-expire<br>–hashlimit-htable-size<br>–hashlimit-htable-max<br><code>``
具体可以</code>man iptables`</p>
<p>#此文仅做备份</p>
]]></content>
<summary type="html">
<p>#引言</p>
<blockquote>
<p>iptables是用来设置、维护和检查Linux内核的IP包过滤规则的,iptables可以定义不同的表,每个表都包含几个内部的链,也能包含用户定义的链。<br>hashlimit是iptables的一个匹配模块,用它结合ip
</summary>
</entry>
<entry>
<title>Swift3.0-iOS碎片记录</title>
<link href="http://roron0a.github.io/2017/05/11/Swift3-0-iOS%E7%A2%8E%E7%89%87%E8%AE%B0%E5%BD%95/"/>
<id>http://roron0a.github.io/2017/05/11/Swift3-0-iOS碎片记录/</id>
<published>2017-05-10T16:52:49.000Z</published>
<updated>2017-05-15T13:08:46.000Z</updated>
<content type="html"><![CDATA[<p>#Optional</p>
<p>都说Swift是门<strong>安全性</strong>的语言 那么它的<strong>安全</strong>体现在哪?</p>
<p>看过文档的我们不会对 <code>!</code> 和 <code>?</code> 陌生</p>
<p><strong>这就是Swift语言队安全性的检测</strong></p>
<p>首先我们看他们的定义</p>
<hr>
<p>When working with optional values, you can write ? before operations like methods, properties, and subscripting. If the value before the ? is nil, everything after the ? is ignored and the value of the whole expression is nil. Otherwise, the optional value is unwrapped, and everything after the ? acts on the unwrapped value. In both cases, the value of the whole expression is an optional value.</p>
<p>Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value (…)</p>
<hr>
<p>说人话就是<br>在<code>optioanal</code>的时候 <strong>当你写下<code>?</code> 如果这个值是<code>nil</code> 那么<code>?</code>之后的语句就被忽略了 整个表达式的值就是<code>nil</code></strong><br>否则<strong>这个值就被<code>unwrapped</code>给解包了 <code>?</code>之后的行为都是根据这个<code>unwrapped</code>值所决定</strong><br>共同点就是 整个表达式的值也是个<code>optioanl value</code></p>
<p>在<code>force unwrapped</code>的时候<br>**如果你确定这个值是确定存在的 那就写下<code>!</code></p>
<p>至于<code>optional</code> 我们可以查看<code>API</code>看到<br>其实是一个<code>enum</code></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">enum Optional<Wrapped> : ExpressibleByNilLiteral</div><div class="line"></div><div class="line">enum Optional<T> {</div><div class="line"> case None</div><div class="line"> case Some(T)</div><div class="line">}</div></pre></td></tr></table></figure>
<p>可见 要么是<code>None</code> 要么是<code>T</code><br>当然我们也可以给<code>optional</code>一个默认值<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">var errorCode:String = '404'</div></pre></td></tr></table></figure></p>
<p>这样 解包<code>errorCode</code>的时候 如果没有值 则会默认给<code>404</code></p>
<h1 id="guard"><a href="#guard" class="headerlink" title="guard"></a>guard</h1><p>实际项目中 很多的 </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">if let optional = optional {</div><div class="line">//some code</div><div class="line"> } else {</div><div class="line">}</div><div class="line">if let optional = optional {</div><div class="line">//some code</div><div class="line"> } else {</div><div class="line">}</div><div class="line">if let optional = optional {</div><div class="line">//some code</div><div class="line"> } else {</div><div class="line">}</div></pre></td></tr></table></figure>
<p>非常繁琐 进而引入了 <code>guard</code><br>常见的就是判断<code>json</code>数据是否有值</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">guard let returnValue = response else { return }</div><div class="line">do {</div><div class="line">/// some code here</div><div class="line">} catch {</div><div class="line">/// some code here</div><div class="line">}</div></pre></td></tr></table></figure>
<p>又或者是判断是否满足条件</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">func checkCondition() throws{</div><div class="line"> guard conditionOne else {</div><div class="line"> throw NotMetConditionOne</div><div class="line"> }</div><div class="line"></div><div class="line"> guard conditionTwo else {</div><div class="line"> throw NotMetConditionTwo </div><div class="line"> }</div><div class="line">//met all condition</div><div class="line"> finalFunction()</div><div class="line">}</div></pre></td></tr></table></figure>
<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">if let some = some</div></pre></td></tr></table></figure></p>
<p>不是特别多比如就二三个。还是用<code>if let</code>方便</p>
<p>参考地址 <a href="">https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html</a></p>
<p><a href="">https://en.wikipedia.org/wiki/Option_type</a></p>
<p><a href="">http://nshipster.com/guard-and-defer/</a></p>
]]></content>
<summary type="html">
<p>#Optional</p>
<p>都说Swift是门<strong>安全性</strong>的语言 那么它的<strong>安全</strong>体现在哪?</p>
<p>看过文档的我们不会对 <code>!</code> 和 <code>?</code> 陌生</p>
<
</summary>
</entry>
<entry>
<title>shadowsocks科学上网以及BBR加速的配置.md</title>
<link href="http://roron0a.github.io/2017/05/07/shadowsocks%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91%E4%BB%A5%E5%8F%8ABBR%E5%8A%A0%E9%80%9F%E7%9A%84%E9%85%8D%E7%BD%AE-md/"/>
<id>http://roron0a.github.io/2017/05/07/shadowsocks科学上网以及BBR加速的配置-md/</id>
<published>2017-05-07T03:11:25.000Z</published>
<updated>2017-05-07T03:11:50.000Z</updated>
<content type="html"><![CDATA[<blockquote>
<blockquote>
<p> 此篇记录下搭建ss和bbr需要的步骤 仅作备份。</p>
</blockquote>
</blockquote>
<h1 id="安装shadowsocks"><a href="#安装shadowsocks" class="headerlink" title="安装shadowsocks"></a>安装shadowsocks</h1><p><em>Dibian/Ubuntu</em><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">apt-get install python-pip</div><div class="line">pip install shadowsocks</div></pre></td></tr></table></figure></p>
<p><em>CentOS</em><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">yum install python-setuptools && easy_install pip</div><div class="line">pip install shadowsocks</div></pre></td></tr></table></figure></p>
<h2 id="编写shadowsocks配置文件"><a href="#编写shadowsocks配置文件" class="headerlink" title="编写shadowsocks配置文件"></a>编写shadowsocks配置文件</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">vi /etc/shadowsocks.json</div></pre></td></tr></table></figure>
<p>其中里面的密码 端口以及加密方式自己设置<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></pre></td><td class="code"><pre><div class="line">"port_password": {</div><div class="line"> "port":"password"</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h3 id="接着-后台启动或关闭shadowosocks-我个人没有设置supervisord"><a href="#接着-后台启动或关闭shadowosocks-我个人没有设置supervisord" class="headerlink" title="接着 后台启动或关闭shadowosocks 我个人没有设置supervisord"></a>接着 后台启动或关闭shadowosocks 我个人没有设置supervisord</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">ssserver -c /etc/shadowsocks.json -d start ssserver -c /etc/shadowsocks.json -d stop</div></pre></td></tr></table></figure>
<p><strong>BBR锐速</strong><br>系统支持:CentOS 6+,Debian 7+,Ubuntu 12+<br>虚拟技术:OpenVZ 以外的,比如 KVM、Xen、VMware 等<br>内存要求:≥128M</p>
<p>我自己的linode Japan 2 低配 Ubutun16.04已经成功使用</p>
<h1 id="root登陆后"><a href="#root登陆后" class="headerlink" title="root登陆后"></a>root登陆后</h1><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 https://github.com/teddysun/across/raw/master/bbr.sh</div><div class="line">chmod +x bbr.sh</div><div class="line">./bbr.sh</div></pre></td></tr></table></figure>
<p>安装后按照步骤重启vps 重启后验证是否成功安装内核并开启<code>TCP BBR</code><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">uname -r</div></pre></td></tr></table></figure></p>
<p>查看内核版本 如果有4.10就表示安装成功</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">sysctl net.ipv4.tcp_available_congestion_control</div></pre></td></tr></table></figure>
<p>返回值一般是 <code>net.ipv4.tcp_available_congestion_control = bbr cubic reno</code></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">sysctl net.ipv4.tcp_congestion_control</div></pre></td></tr></table></figure>
<p>返回值一般是 <code>net.ipv4.tcp_congestion_control = bbr</code></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">sysctl net.core.default_qdisc</div></pre></td></tr></table></figure>
<p>返回值一般是 <code>net.core.default_qdisc = fq</code></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">lsmod | grep bbr</div></pre></td></tr></table></figure></p>
<p>如果返回值含有 <code>tcp_bbr</code>则表示<code>BBR</code>已经启动</p>
]]></content>
<summary type="html">
<blockquote>
<blockquote>
<p> 此篇记录下搭建ss和bbr需要的步骤 仅作备份。</p>
</blockquote>
</blockquote>
<h1 id="安装shadowsocks"><a href="#安装shadowsocks" cla
</summary>
</entry>
<entry>
<title>ObjC中initialize的本质</title>
<link href="http://roron0a.github.io/2017/05/04/ObjC%E4%B8%ADinitialize%E7%9A%84%E6%9C%AC%E8%B4%A8/"/>
<id>http://roron0a.github.io/2017/05/04/ObjC中initialize的本质/</id>
<published>2017-05-04T13:33:08.000Z</published>
<updated>2017-05-04T13:33:15.000Z</updated>
<content type="html"><![CDATA[<p><strong>熟悉ObjC的不会对<code>load</code>和<code>initialize</code>陌生。我们这次就来说下它们的区别</strong></p>
<p><strong>我们知道 <code>initialize</code>是<code>lazy-loading</code>的 也就是说 除非主动给类发消息,无论是实例方法或者是类方法。 否则<code>initialize</code>是不会调用的</strong></p>
<p>我们看下<code>initialize</code>的调用栈</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">Object initialize</div><div class="line">_class initialize</div><div class="line">lookupImpOrForward</div><div class="line">_class_lookupMethodAndLocateCache3</div><div class="line">objc_msgSend</div><div class="line">main</div><div class="line">start</div></pre></td></tr></table></figure>
<p><strong>从之前的文章我们知道。<code>lookupImpOrForward</code>只会向对象发送消息并且在类的缓存里没有找到对应的<code>SEL</code>才会调用 而且<code>lookupImpOrForward</code>是<code>objc_msgSend</code>的触发器</strong></p>
<p>我们在这里用<code>lldb</code>打印下 <code>sel</code>看他调用的是什么选择子</p>
<p>我们看到是 <code>alloc</code>方法</p>
<p>所以 <code>initialize</code>是在<code>alloc</code>之前调用的 后者导致了前者的执行</p>
<p><code>if (initialize && !cls->isInitialized())</code>来看是否初始化过</p>
<p>接下来我们看下<code>lookupImpOrForward</code>是什么东西<br><strong>通过下面的代码片段 我们知道 runtime会找对应的方法实现,或者进行消息转发,其中如果类没有初始化,则会通过<code>void_class_initialize(Class cls))</code>函数进行初始化</strong></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">IMP lookUpImpOrForward(Class cls, SEL sel, id inst,</div><div class="line"> bool initialize, bool cache, bool resolver)</div><div class="line">{</div><div class="line"> ...</div><div class="line"> rwlock_unlock_write(&runtimeLock);</div><div class="line"> }</div><div class="line"></div><div class="line"> if (initialize && !cls->isInitialized()) {</div><div class="line"> _class_initialize (_class_getNonMetaClass(cls, inst));</div><div class="line"> // If sel == initialize, _class_initialize will send +initialize and </div><div class="line"> // then the messenger will send +initialize again after this </div><div class="line"> // procedure finishes. Of course, if this is not being called </div><div class="line"> // from the messenger then it won't happen. 2778172</div><div class="line"> }</div><div class="line"></div><div class="line"> // The lock is held to make method-lookup + cache-fill atomic </div><div class="line"> // with respect to method addition. Otherwise, a category could </div><div class="line"> ...</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>其中对父类进行递归调用 确保父类优于子类初始化<br>并且在<br><code>((void(*)(Class,SEL))objc_msgSend)(cls,SEL_initialize);</code><br>使用了runtime的发送消息的方法,对<code>initialize</code>进行了调用。也就是说,<code>initialize</code>和普通方法的调用是一致的,都是<code>objc_msgSend</code>的机制</strong><br>即<br><em>如果子类没有实现<code>initialize</code>方法则调用父类的<code>initialize</code> (注意,此操作会循环调用)
</em>如果一个类的分类实现了<code>initialize</code>则会覆盖该类的实现</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><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line">void _class_initialize(Class cls)</div><div class="line">{</div><div class="line"> ...</div><div class="line"> Class supercls;</div><div class="line"> BOOL reallyInitialize = NO;</div><div class="line"></div><div class="line"> // Make sure super is done initializing BEFORE beginning to initialize cls.</div><div class="line"> // See note about deadlock above.</div><div class="line"> supercls = cls->superclass;</div><div class="line"> if (supercls && !supercls->isInitialized()) {</div><div class="line"> _class_initialize(supercls);</div><div class="line"> }</div><div class="line"></div><div class="line"> // Try to atomically set CLS_INITIALIZING.</div><div class="line"> monitor_enter(&classInitLock);</div><div class="line"> if (!cls->isInitialized() && !cls->isInitializing()) {</div><div class="line"> cls->setInitializing();</div><div class="line"> reallyInitialize = YES;</div><div class="line"> }</div><div class="line"> monitor_exit(&classInitLock);</div><div class="line"></div><div class="line"> if (reallyInitialize) {</div><div class="line"> // We successfully set the CLS_INITIALIZING bit. Initialize the class.</div><div class="line"></div><div class="line"> // Record that we're initializing this class so we can message it.</div><div class="line"> _setThisThreadIsInitializingClass(cls);</div><div class="line"></div><div class="line"> // Send the +initialize message.</div><div class="line"> // Note that +initialize is sent to the superclass (again) if </div><div class="line"> // this class doesn't implement +initialize. 2157218</div><div class="line"> if (PrintInitializing) {</div><div class="line"> _objc_inform("INITIALIZE: calling +[%s initialize]",</div><div class="line"> cls->nameForLogging());</div><div class="line"> }</div><div class="line"></div><div class="line"> ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);</div><div class="line"></div><div class="line"> if (PrintInitializing) {</div><div class="line"> _objc_inform("INITIALIZE: finished +[%s initialize]",</div></pre></td></tr></table></figure>
<p>为了避免父类的<code>initialize</code>多次调用 我们用以下代码来操作</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">+(void)initialize {</div><div class="line"> if(self ==[ClassName self]) {</div><div class="line"> // initialize the class</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<blockquote>
<p>我们再看以下<code>lookupImpOrForward</code>里的具体实现</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">bool isInitialized() {</div><div class="line"> return getMeta()->data()->flags & RW_INITIALIZED;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>可见判断初始化的信息保存在<code>class_rw_t</code>结构体里的<code>flags</code><br>数据结构</p>
<p><strong>上面我们知道 直接发消息的是下面这个C函数</strong></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><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div></pre></td><td class="code"><pre><div class="line">void _class_initialize(Class cls)</div><div class="line">{</div><div class="line"> Class supercls;</div><div class="line"> BOOL reallyInitialize = NO;</div><div class="line"> </div><div class="line"> supercls = cls->superclass;// 1 .父类优于子类</div><div class="line"> if(supercls && !supercls->isInitialized()) {</div><div class="line"> _class_initialize(supercls);</div><div class="line"> }</div><div class="line"> </div><div class="line"> {</div><div class="line"> monitor_locker_t lock(classInitLock); // 2. 用锁来设置 RW_initialization的标志位</div><div class="line"> if(!cls->isInitialize() && !cls->isInitializing()) {</div><div class="line"> cls->setInitializing();</div><div class="line"> reallyInitialize = YES;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> </div><div class="line"> if(reallyInitialize) {</div><div class="line"> _setThisThreadInitializingClass(cls);</div><div class="line"> // 3. 标志位设置成功,则对该类发送`initialize`的消息。像调用其他OC方法一样是`objc_msgSend`</div><div class="line"> ((void (*)(Class,SEL))objc_msgSend)(cls,SEL_initialize);</div><div class="line"> </div><div class="line"> </div><div class="line"> </div><div class="line"> monitor_locker_t lock(classinitLock);</div><div class="line"> if(!supercls || supercls->isInitialized()) {</div><div class="line"> // 4. 如果父类完成了初始化,则设置 RW_INITIALIZED 标志位。记得 一定是`父类优于子类`</div><div class="line"> _finishInitializing(cls,supercls);</div><div class="line"> } else {</div><div class="line"> _finishInitializingAfter(cls,supercls);</div><div class="line"> }</div><div class="line"> } else if (cls->isInitializing()) {</div><div class="line"> </div><div class="line"> if(_thisThreadIsInitializingClass(cls)) {</div><div class="line"> return;// 5.1 如果当前线程正在初始化当前的类,则直接返回</div><div class="line"> } else { </div><div class="line"> // 5.2 否则 等待其他线程结束 再返回</div><div class="line"> monitor_locker_t lock(classInitLock);</div><div class="line"> while(!cls->isInitialized()) {</div><div class="line"> classInitLock.wait();</div><div class="line"> }</div><div class="line"> return;</div><div class="line"> }</div><div class="line"> } else if(cls->isInitialized)) {</div><div class="line"> return; // 6 当前类初始化完成,直接返回</div><div class="line"> }</div><div class="line"> } else {</div><div class="line"> objc_fatal("thread-safe class init in objc runtime is buggy");</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>我们可以得出结论 <code>_class_initialize</code>是向没有初始化的类 发送 <code>+initialize</code>消息 但是会强制父类先发送<code>+initialize</code>消息 之前的结论 <strong>父类优于子类</strong></p>
<blockquote>
<p>那么ObjC是如何确保 父类的调用优于子类 ?</p>
</blockquote>
<p><strong>我们引入管理初始化队列这个概念</strong><br>为了保证父类的初始化方法在子类之前调用 我们维护一个 <code>pendingInitializeMap</code>的数据结构 来决定当前类的初始化需要哪个父类先初始化完成</p>
<p>其中上述代码里的 </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">if(!supercls || supercls->isInitialized()) {</div><div class="line"> _finishInitializing(cls,supercls);</div><div class="line">} else {</div><div class="line"> _finishInitializingAfter(cls,supercls));</div><div class="line">}</div></pre></td></tr></table></figure>
<p>会改变 <code>PendingInitialzeMap</code>的数据结构 我们看一下这两个方法的实现 首先看<strong>父类没有初始化</strong>时候的操作</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></pre></td><td class="code"><pre><div class="line">static void _finishInitializingAfter(Class cls,Class supercls)</div><div class="line">{</div><div class="line"> PendingInitialize *pending;</div><div class="line"> pending = (PendingIntialize *)malloc(sizeof(*pending));</div><div class="line"> pending->subclass = cls;</div><div class="line"> pending->next = (PendingInitialize *)NXMapGet(pendingInitializeMap,supercls);</div><div class="line"> NXMapInsert(pendingInitializeMap,supercls,pending);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>**由于父类没有初始化,所以我们把子类加入到一个<code>PendingInitialize</code>的数据结构里面<br>这个数据结构会以<code>父类</code>为键存储到<code>pendingInitializeMap</code>里面</p>
<p>再看一下<strong>父类已经初始化</strong>的情况</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">static void _finishIntializing(Class cls,Class supercls)</div><div class="line">{</div><div class="line"> PendingInitialize *pending;</div><div class="line"> cls->setInitialized(); // 由于已经初始化,我们在这里标记当前类</div><div class="line"> </div><div class="line"> //递归把当前类的block的子类标记为初始化 然而把当前类移除数据结构</div><div class="line"> if(!pendingInitializeMap) return;</div><div class="line"> pending = (PendingInitialize *)NXMapGet(pendingInitializeMap,cls);</div><div class="line"> if(!pending) return;</div><div class="line"> </div><div class="line"> NXMapRemove(pendingInitializeMap,cls);</div><div class="line"> </div><div class="line"> while(pending) {</div><div class="line"> PendingInitialize *next = pending->next;</div><div class="line"> if(pending->subclass) _finishInitializing(pending->subclass,cls);</div><div class="line"> free(pending);</div><div class="line"> pending = next;</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>Summary</strong><br>1 <code>initialize</code>只会在第一次调用这个类的方法时候调用<br>2 <code>initialize</code>调用时 <strong>所有的类</strong>都加在到了内存里<br>3 <code>initialize</code> is <strong>thread-safe</strong><br>4 子类会<strong>继承</strong>父类的<code>initialize</code> 所以我们一般会用<code>load</code>来动态添加方法 ,而不是<code>initialize</code>因为后者会造成循环调用。<br>**一般我们用<code>initialize</code>的时候 只是进行一些简单的初始化。</p>
<blockquote>
<p>参考</p>
</blockquote>
<p>NSObject +load and +initialize - What do they do?<br><a href="http://stackoverflow.com/questions/13326435/nsobject-load-and-initialize-what-do-they-do" target="_blank" rel="external">http://stackoverflow.com/questions/13326435/nsobject-load-and-initialize-what-do-they-do</a><br>懒惰的 initialize 方法<br><a href="http://draveness.me/initialize/" target="_blank" rel="external">http://draveness.me/initialize/</a><br>Objective-C +load vs +initialize<br><a href="http://blog.leichunfeng.com/blog/2015/05/02/objective-c-plus-load-vs-plus-initialize/" target="_blank" rel="external">http://blog.leichunfeng.com/blog/2015/05/02/objective-c-plus-load-vs-plus-initialize/</a></p>
]]></content>
<summary type="html">
<p><strong>熟悉ObjC的不会对<code>load</code>和<code>initialize</code>陌生。我们这次就来说下它们的区别</strong></p>
<p><strong>我们知道 <code>initialize</code>是<code>la
</summary>
</entry>
<entry>
<title>Obj-C中load方法的本质</title>
<link href="http://roron0a.github.io/2017/05/04/Obj-C%E4%B8%ADload%E6%96%B9%E6%B3%95%E7%9A%84%E6%9C%AC%E8%B4%A8/"/>
<id>http://roron0a.github.io/2017/05/04/Obj-C中load方法的本质/</id>
<published>2017-05-04T13:28:10.000Z</published>
<updated>2017-05-04T13:28:31.000Z</updated>
<content type="html"><![CDATA[<p><strong><code>load</code>方法和<code>initialize</code>的讨论也是很多的,这次我们先看下<code>load</code>方法的底层到底如何实现</strong></p>
<p><strong>熟悉ObjC本质,即熟悉<code>runtime</code>的 对<code>load</code>方法都不会陌生,它是在类<code>被加载到运行时</code>的时候被调用的一个<code>hook</code>方法以及<code>父类优于子类,子类优于分类</code></strong></p>
<blockquote>
<p>我们看一下<code>load</code>方法的调用栈</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><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">@interface Fuck : NSObject</div><div class="line"></div><div class="line">@end</div><div class="line"></div><div class="line">@implementation Fuck</div><div class="line">+(void)load {</div><div class="line"> NSLog("fuck is loaded");</div><div class="line">}</div><div class="line">@end</div><div class="line"></div><div class="line">int main(int argc, const char *argv[]) {</div><div class="line"> @autoreleasepool {}</div><div class="line"> return 0;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>运行后我们会看到控制台简单的输出了 <code>fuck is loaded</code>这个字符串 </p>
<p>接下来我们在<code>load</code>方法那里 打个断点</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">+[Fuck load]</div><div class="line">call_class_loads()</div><div class="line">call_load_methods</div><div class="line">load_images</div><div class="line">dyld::notifySingle(dyld_image_states,ImageLoader const*)</div><div class="line">_dyld_start</div></pre></td></tr></table></figure>
<p><code>call_class_load()</code>和<code>call_load_methods</code>顾名思义 我们看一下这个<code>load_image</code>到底是什么</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><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div></pre></td><td class="code"><pre><div class="line">const char * </div><div class="line">load_images(enum dyld_image_states state, uint32_t infoCount, </div><div class="line"> const struct dyld_image_info infoList[])</div><div class="line">{</div><div class="line"> bool found;</div><div class="line"></div><div class="line"> found = false;</div><div class="line"> for (uint32_t i = 0; i < infoCount; i++) {</div><div class="line"> //这里判断是否有 **load**方法</div><div class="line"> if (hasLoadMethods((const headerType *)infoList[i].imageLoadAddress)) {</div><div class="line"> found = true;</div><div class="line"> break;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> if (!found) return nil;</div><div class="line"></div><div class="line"> recursive_mutex_locker_t lock(loadMethodLock);</div><div class="line"></div><div class="line"> {</div><div class="line"> rwlock_writer_t lock2(runtimeLock);</div><div class="line"> found = load_images_nolock(state, infoCount, infoList);</div><div class="line"> }</div><div class="line"></div><div class="line"> if (found) {</div><div class="line"> call_load_methods();</div><div class="line"> }</div><div class="line"></div><div class="line"> return nil;</div><div class="line">}</div><div class="line"></div><div class="line">bool load_images_nolock(enum dyld_image_states state,uint32_t infoCount, </div><div class="line"> const struct dyld_image_info infoList[])</div><div class="line">{</div><div class="line"> bool found = NO;</div><div class="line"> uint32_t i;</div><div class="line"></div><div class="line"> i = infoCount;</div><div class="line"> while (i--) {</div><div class="line"> const headerType *mhdr = (headerType*)infoList[i].imageLoadAddress;</div><div class="line"> //是否有**load**方法</div><div class="line"> if (!hasLoadMethods(mhdr)) continue;</div><div class="line"></div><div class="line"> prepare_load_methods(mhdr);</div><div class="line"> found = YES;</div><div class="line"> }</div><div class="line"></div><div class="line"> return found;</div><div class="line">}</div><div class="line">//准备给load方法调用的类以及分类</div><div class="line">void prepare_load_methods(const headerType *mhdr) </div><div class="line">{</div><div class="line"> size_t count, i;</div><div class="line"></div><div class="line"> runtimeLock.assertWriting();</div><div class="line"></div><div class="line"> classref_t *classlist = </div><div class="line"> _getObjc2NonlazyClassList(mhdr, &count); //</div><div class="line"> for (i = 0; i < count; i++) {</div><div class="line"> schedule_class_load(remapClass(classlist[i]));</div><div class="line"> }</div><div class="line"></div><div class="line"> category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);</div><div class="line"> for (i = 0; i < count; i++) {</div><div class="line"> category_t *cat = categorylist[i];</div><div class="line"> Class cls = remapClass(cat->cls);</div><div class="line"> if (!cls) continue; // category for ignored weak-linked class</div><div class="line"> realizeClass(cls);</div><div class="line"> assert(cls->ISA()->isRealized());</div><div class="line"> add_category_to_loadable_list(cat);</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line">//上面的 _getObjc2NonlazyClassList获取所有类的list后 然后用 remapClass获取类对应的指针 然后递归的安排类和当前类的弗雷进入列表</div><div class="line">static void schedule_class_load(Class cls) </div><div class="line">{</div><div class="line"> if (!cls) return;</div><div class="line"> assert(cls->isRealized());</div><div class="line"></div><div class="line"> if (cls->data()->flags & RW_LOADED) return;</div><div class="line"></div><div class="line"> schedule_class_load(cls->superclass);</div><div class="line"> //先把父类加入到待加载的列表里 保证父类先调用load方法</div><div class="line"> add_class_to_loadable_list(cls);</div><div class="line"> cls->setInfo(RW_LOADED); </div><div class="line">}</div></pre></td></tr></table></figure>
<p>**这时 <code>load</code>方法的调用已经就绪 ObjC会执行<code>call_load_methods</code></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></pre></td><td class="code"><pre><div class="line">调用之前的`prepare_load_methods`里准备好的类以及分类里的load方法 并且确保了优先级</div><div class="line">void call_load_methods(void) </div><div class="line">{</div><div class="line"> ...</div><div class="line"></div><div class="line"> do {</div><div class="line"> while (loadable_classes_used > 0) {</div><div class="line"> call_class_loads();</div><div class="line"> }</div><div class="line"></div><div class="line"> more_categories = call_category_loads();</div><div class="line"></div><div class="line"> } while (loadable_classes_used > 0 || more_categories);</div><div class="line"></div><div class="line"> ...</div><div class="line">}</div></pre></td></tr></table></figure>
<p>**其中待加载的类会在<code>loadable_classes</code>中寻找对应的类 然后找到<code>load</code>选择子进行执行</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></pre></td><td class="code"><pre><div class="line">顾名思义 这个才是负责调用load方法的真正函数</div><div class="line">static void call_class_loads(void) </div><div class="line">{</div><div class="line"> int i;</div><div class="line"></div><div class="line"> struct loadable_class *classes = loadable_classes;</div><div class="line"> int used = loadable_classes_used;</div><div class="line"> //取出可调用的类 并进行清零</div><div class="line"> loadable_classes = nil;</div><div class="line"> loadable_classes_allocated = 0;</div><div class="line"> loadable_classes_used = 0;</div><div class="line"></div><div class="line"> for (i = 0; i < used; i++) {</div><div class="line"> Class cls = classes[i].cls;</div><div class="line"> load_method_t load_method = (load_method_t)classes[i].method;</div><div class="line"> if (!cls) continue;</div><div class="line">//调用 [Fuck load]的关键 注意,这里不是`objc_msgSend`的形式调用 而是直接使用函数的内存地址</div><div class="line"> (*load_method)(cls, SEL_load);</div><div class="line"> }</div><div class="line"></div><div class="line"> if (classes) free(classes);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>**可见 <code>load</code>方法是在ObjC进行初始化的时候通过动态链接,执行<code>load_images</code> 对其所拥有<code>load</code>方法的文件加入到 <code>loadable_classes</code>里面 然后通过这个列表递归的找到对应的<code>load</code>选择子 进行执行</p>
<blockquote>
<p>那么<code>loadale_classes</code>到底是如何管理的?</p>
</blockquote>
<p>我们从上面的 <code>call_load_methods</code>里可以看到 加载的管理主要是两个表 那么方法的调用过程也自然是两个部分 一个是加载方法 一个是调用方法(命名方法不难得出)</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></pre></td><td class="code"><pre><div class="line">load_images</div><div class="line"> load_images_nolock</div><div class="line"> prepare_load_methods</div><div class="line"> schedule_class_load</div><div class="line"> add_class_to_loadable_list</div><div class="line"> loadable_classes++</div></pre></td></tr></table></figure></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></pre></td><td class="code"><pre><div class="line">void add_class_to_loadable_list(Class cls) </div><div class="line">{</div><div class="line"> IMP method;</div><div class="line"></div><div class="line"> loadMethodLock.assertLocked();</div><div class="line"></div><div class="line"> method = cls->getLoadMethod();// 1 从cls里面获取load方法</div><div class="line"> if (!method) return;</div><div class="line"></div><div class="line"> if (loadable_classes_used == loadable_classes_allocated) { // 2 判断数组是否全部占用</div><div class="line"> loadable_classes_allocated = loadable_classes_allocated*2 + 16; // 3 扩充数组的大小</div><div class="line"> loadable_classes = (struct loadable_class *)</div><div class="line"> realloc(loadable_classes,</div><div class="line"> loadable_classes_allocated *</div><div class="line"> sizeof(struct loadable_class));</div><div class="line"> }</div><div class="line"></div><div class="line">// 4 把传入的cls和对应的方法实现加入到列表里 loadable_classes[loadable_classes_used].cls = cls;</div><div class="line"> loadable_classes[loadable_classes_used].method = method;</div><div class="line"> loadable_classes_used++;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>同理不难得出<code>loadable_categories</code>的实现</p>
<p>执行<code>load</code>方法</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><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line">void call_load_methods(void) </div><div class="line">{</div><div class="line"> static bool loading = NO;</div><div class="line"> bool more_categories;</div><div class="line"></div><div class="line"> loadMethodLock.assertLocked();</div><div class="line"></div><div class="line"> if (loading) return;</div><div class="line"> loading = YES;</div><div class="line"></div><div class="line"> void *pool = objc_autoreleasePoolPush();</div><div class="line"></div><div class="line"> do {</div><div class="line"> while (loadable_classes_used > 0) {</div><div class="line"> call_class_loads();</div><div class="line"> }</div><div class="line"></div><div class="line"> more_categories = call_category_loads();</div><div class="line"></div><div class="line"> } while (loadable_classes_used > 0 || more_categories);</div><div class="line">// 递归的调用类的load方法 直到loadable_classes为空</div><div class="line">// 对于分类的load方法 这里只调用一次</div><div class="line"> objc_autoreleasePoolPop(pool);</div><div class="line"></div><div class="line"> loading = NO;</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>然而 对于分类的<code>load</code>方法 这里会复杂很多 我们看下它的调用栈并逐一分析</strong></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><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div></pre></td><td class="code"><pre><div class="line">static bool call_category_loads(void) </div><div class="line">{</div><div class="line"> int i, shift;</div><div class="line"> bool new_categories_added = NO;</div><div class="line"> // 1 可以加载的分类列表</div><div class="line"> struct loadable_category *cats = loadable_categories;</div><div class="line"> int used = loadable_categories_used;</div><div class="line"> int allocated = loadable_categories_allocated;</div><div class="line"> loadable_categories = nil;</div><div class="line"> loadable_categories_allocated = 0;</div><div class="line"> loadable_categories_used = 0;</div><div class="line"></div><div class="line"> for (i = 0; i < used; i++) {</div><div class="line"> Category cat = cats[i].cat;</div><div class="line"> load_method_t load_method = (load_method_t)cats[i].method;</div><div class="line"> Class cls;</div><div class="line"> if (!cat) continue;</div><div class="line"> cls = _category_getClass(cat);</div><div class="line"> if (cls && cls->isLoadable()) {</div><div class="line"> // 2 调用分类的load方法</div><div class="line"> (*load_method)(cls, SEL_load);</div><div class="line"> cats[i].cat = nil;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> // 3 把加载过load方法的分类 移除列表</div><div class="line"> shift = 0;</div><div class="line"> for (i = 0; i < used; i++) {</div><div class="line"> if (cats[i].cat) {</div><div class="line"> cats[i-shift] = cats[i];</div><div class="line"> } else {</div><div class="line"> shift++;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> used -= shift;</div><div class="line"></div><div class="line"> // 4 重置家在列表</div><div class="line"> new_categories_added = (loadable_categories_used > 0);</div><div class="line"> for (i = 0; i < loadable_categories_used; i++) {</div><div class="line"> if (used == allocated) {</div><div class="line"> allocated = allocated*2 + 16;</div><div class="line"> cats = (struct loadable_category *)</div><div class="line"> realloc(cats, allocated *</div><div class="line"> sizeof(struct loadable_category));</div><div class="line"> }</div><div class="line"> cats[used++] = loadable_categories[i];</div><div class="line"> }</div><div class="line"></div><div class="line"> if (loadable_categories) free(loadable_categories);</div><div class="line"></div><div class="line"> if (used) {</div><div class="line"> loadable_categories = cats;</div><div class="line"> loadable_categories_used = used;</div><div class="line"> loadable_categories_allocated = allocated;</div><div class="line"> } else {</div><div class="line"> if (cats) free(cats);</div><div class="line"> loadable_categories = nil;</div><div class="line"> loadable_categories_used = 0;</div><div class="line"> loadable_categories_allocated = 0;</div><div class="line"> }</div><div class="line"></div><div class="line"> return new_categories_added;</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>我们在开头里面说过 <code>父类优于子类,子类优于分类</code><br>接下来我们分析这个说法</strong></p>
<p>前面的 <code>schedule_class_load(Class cls)</code>的实现,其中 <code>schedule_class_load(cls->superclass</code>就确保了 <code>父类优于子类</code></p>
<p>后面的 <code>call_load_methods</code>的实现 <code>do while</code>不能完全确保 <code>子类优于分类</code> 所以就有了 <code>call_category_loads</code> 判断类是否加载到了内存里面 我们看下代码片段</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">if(cls && cls->isLoadable)) {</div><div class="line"> (*load_method)(cls,SEL_load);</div><div class="line"> cats[i].cat = nil;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>这样 我们就确保了 <code>子类优于分类</code>这个条件</p>
<blockquote>
<p><strong>总结</strong></p>
</blockquote>
<p>通过上面的各种分析和调用 我们知道<code>load</code>方法是优于<code>main</code>函数的 而且<code>load</code>的非惰性加载以及<code>类</code>和<code>分类</code>的调用并不会冲突 这就成了黑魔法<code>method swizzle</code>的最好时间</p>
<blockquote>
<p>参考</p>
</blockquote>
<p>NSObject +load and +initialize - What do they do<br><a href="http://stackoverflow.com/questions/13326435/nsobject-load-and-initialize-what-do-they-do" target="_blank" rel="external">http://stackoverflow.com/questions/13326435/nsobject-load-and-initialize-what-do-they-do</a><br>Objective-C +load vs +initialize<br><a href="http://blog.leichunfeng.com/blog/2015/05/02/objective-c-plus-load-vs-plus-initialize/" target="_blank" rel="external">http://blog.leichunfeng.com/blog/2015/05/02/objective-c-plus-load-vs-plus-initialize/</a><br>你真的了解 load 方法么?<br><a href="http://draveness.me/load/" target="_blank" rel="external">http://draveness.me/load/</a></p>
]]></content>
<summary type="html">
<p><strong><code>load</code>方法和<code>initialize</code>的讨论也是很多的,这次我们先看下<code>load</code>方法的底层到底如何实现</strong></p>
<p><strong>熟悉ObjC本质,即熟悉<code
</summary>
</entry>
<entry>
<title>Obj-C中的class_object</title>
<link href="http://roron0a.github.io/2017/05/04/Obj-C%E4%B8%AD%E7%9A%84class-object/"/>
<id>http://roron0a.github.io/2017/05/04/Obj-C中的class-object/</id>
<published>2017-05-04T13:21:33.000Z</published>
<updated>2017-05-04T13:21:53.000Z</updated>
<content type="html"><![CDATA[<p><strong>本文仅对ObjC的<code>class</code>以及<code>instance</code>的本质进行分析</strong></p>
<hr>
<blockquote>
<p>先放出结论,ObjC的类和实例对象 都是对象<br>类是<code>metaClass</code>的实例对象<br>听起来有点绕,我们下面进行逐一分析。</p>
</blockquote>
<p><strong>首先,我们先看<code>objc_object</code>和<code>objc_class</code>这两个结构体</strong></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><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">typdef struct objc_class *Class;</div><div class="line">typdef struct objc_object *id; //不会陌生</div><div class="line">//Class和id的数据结构</div><div class="line">//Represents an instance of a class.</div><div class="line">struct objc_object {</div><div class="line"> isa_t isa;</div><div class="line">};</div><div class="line">//A pointer to an instance of a class.</div><div class="line">struct objc_class : objc_object{</div><div class="line"> isa_t isa;</div><div class="line"> Class superclass;</div><div class="line"> cache_t cache;</div><div class="line"> class_data_bits_t bits; //class_rw_t * plust custom rr/alloc flags</div><div class="line">}</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line">class_rw_t data() {</div><div class="line"> return (class_rw_t *)(bits & FAST_DATA_MASK);</div><div class="line">}</div><div class="line"></div><div class="line">struct class_rw_t { </div><div class="line"> uint32_t flags;</div><div class="line"> uint32_t version;</div><div class="line"></div><div class="line"> const class_ro_t *ro; //常量指针</div><div class="line"></div><div class="line"> method_array_t methods;</div><div class="line"> property_array_t properties;</div><div class="line"> protocol_array_t protocols;</div><div class="line"></div><div class="line"> Class firstSubclass;</div><div class="line"> Class nextSiblingClass;</div><div class="line">};</div><div class="line"></div><div class="line">struct class_ro_t { </div><div class="line"> uint32_t flags;</div><div class="line"> uint32_t instanceStart;</div><div class="line"> uint32_t instanceSize;</div><div class="line"> uint32_t reserved;</div><div class="line"></div><div class="line"> const uint8_t * ivarLayout;</div><div class="line"></div><div class="line"> const char * name;</div><div class="line"> method_list_t * baseMethodList;</div><div class="line"> protocol_list_t * baseProtocols;</div><div class="line"> const ivar_list_t * ivars;</div><div class="line"></div><div class="line"> const uint8_t * weakIvarLayout;</div><div class="line"> property_list_t *baseProperties;</div><div class="line">};</div><div class="line"></div><div class="line">struct objc_ivar_list {</div><div class="line"> int ivar_count;</div><div class="line">#ifdef __LP64__</div><div class="line"> int space;</div><div class="line">#endif</div><div class="line"> struct objc_ivar ivar_list[1];</div><div class="line">};</div><div class="line"></div><div class="line">struct objc_method_list {</div><div class="line"> struct objc_method_list *obsolete;</div><div class="line"> </div><div class="line"> int method_count;</div><div class="line">#ifdef __LP64__</div><div class="line"> int space;</div><div class="line">#endif</div><div class="line"> struct objc_method method_list[1];</div><div class="line">};</div></pre></td></tr></table></figure>
<p><strong>不难看出ObjC中的 属性 方法 以及协议等信息 都存储在<code>class_rw_t</code><br>其中 常量指针<code>ro</code>其结构体为<code>class_ro_t</code>存储了当前类在编译器就已经确定的属性 方法 以及协议</strong></p>
<p><strong>所以我们得出 凡是第一个地址是<code>isa</code>的指针的 都是objc里的对象。我们在运行时是通过这个指针 来确定对象是属于哪个<code>Class</code></strong></p>
<p><strong>那么 ObjC中的 <code>类</code> 也是一个对象(对类发送消息,即调用类方法)。那<code>类</code>在运行时指向的<code>Class</code>又是什么?</strong></p>
<p><strong>接着就是我们开头引入的<code>meta class</code> .</strong></p>
<p><strong>我们知道ObjC对象的方法只是存储在对象结构体里中<code>class_data_bits_t</code>的结构体中。当<code>实例方法</code>被调用的时候,它要通过自己的<code>isa</code>来查找对应的类,然后在<code>class_data_bits_t</code>这个结构体里(<code>class_rw_t</code> <code>class_ro_t</code>)查找方法的实现。同时每一个<code>objc_class</code>也有一个指向自己父类的指针<code>super_class</code>来查找自己所继承的<code>method_list</code></strong></p>
<p><strong>那么类方法的实现是怎样查找和调用?这时就是<code>metaclass</code>来保证无论是<code>class</code>还是<code>object</code>都能通过<code>一样的机制来查找方法的实现</code></strong></p>
<p><code>object
isa_t isa</code><br>d asdasdasd<br><code>RootClass
isa_t isa</code></p>
<p><code>RootMetaClass
isa_t isa</code></p>
<p>这张经典的 <code>Classes and metaclasses</code>的示例图<br><a href="http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html" target="_blank" rel="external">objc expalain:Classes and metaclasses</a><br><strong>虚线代表<code>isa</code>指针的轨迹<br>实线代表<code>class</code>的轨迹</strong><br><img src="http://www.sealiesoftware.com/blog/class%20diagram.pdf" alt=""></p>
<p><strong>每一个类的<code>isa</code>都指向对应的<code>metaClass</code> 这样<code>类方法</code>和<code>实例方法</code>的调用机制的目的就一样了</strong></p>
<ul>
<li>实例方法调用,通过对象的<code>isa</code>在<code>Class</code>中获取实例方法的实现</li>
<li>类方法调用 通过类的<code>isa</code>在<code>metaClass</code>中获取类方法的实现</li>
<li>最终<code>RootClass</code>的<code>superclass</code>则为nil 形成了一个闭环</li>
</ul>
<hr>
<p><strong>参考引用</strong><br>*Objective-C 中的类和对象<br><a href="http://blog.ibireme.com/2013/11/25/objc-object/" target="_blank" rel="external">http://blog.ibireme.com/2013/11/25/objc-object/</a><br>从 NSObject 的初始化了解 isa<br><a href="http://draveness.me/isa/" target="_blank" rel="external">http://draveness.me/isa/</a><br>What is a meta-class in Objective-C?<br><a href="https://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html" target="_blank" rel="external">https://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html</a><br>[objc explain]: Classes and metaclasses<br><a href="http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html" target="_blank" rel="external">http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html</a></p>
]]></content>
<summary type="html">
<p><strong>本文仅对ObjC的<code>class</code>以及<code>instance</code>的本质进行分析</strong></p>
<hr>
<blockquote>
<p>先放出结论,ObjC的类和实例对象 都是对象<br>类是<code>met
</summary>
</entry>
</feed>