<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">

<channel>
  <title>Zhixingheyi</title>
  <link>http://foredoomed.org</link>
  <description>The homepage of Zhixingheyi</description>
  <language>zh-cn</language>
  <pubDate>Thu, 08 Feb 2018 14:51:44 +0800</pubDate>
  <lastBuildDate>Thu, 08 Feb 2018 14:51:44 +0800</lastBuildDate>
  <generator>Jekyll</generator>
  <managingEditor>mc.liuxuan@gmail.com (Foredoomed)</managingEditor>
  <webMaster>mc.liuxuan@gmail.com (Foredoomed)</webMaster>

  
  <item>
    <title>定制Manjaro</title>
    <link>http://foredoomed.org/blog/2018/02/08/customizing-manjaro/</link>
    <description>&lt;p&gt;首先官网下载Manjaro的ISO文件，然后用&lt;a href=&quot;http://rufus.akeo.ie/&quot;&gt;rufus&lt;/a&gt;将镜像写入U盘再安装。&lt;/p&gt;

&lt;h2&gt;0. 切换中国源&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo pacman-mirrors -c China
$ sudo pacman-optimize &amp;amp;&amp;amp; sync
$ sudo pacman -Syyu&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;1. 安装archlinuxcn-keyring&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo pacman -S archlinuxcn-keyring&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果安装失败就执行：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo pacman -Syu haveged
$ sudo systemctl start haveged
$ sudo systemctl enable haveged
$ sudo rm -rf /etc/pacman.d/gnupg
$ sudo pacman-key --init
$ sudo pacman-key --populate archlinux
$ sudo pacman -S archlinuxcn-keyring
$ sudo pacman-key --populate archlinuxcn
$ sudo pacman -Syy &amp;amp;&amp;amp; sudo pacman -S archlinuxcn-keyring&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;2. 安装yaourt和pacaur&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo pacman -S yaourt pacaur&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;3. 安装fish shell&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo pacman -S fish
$ chsh -s /usr/bin/fish&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;4. 安装Mac主题&lt;/h2&gt;

&lt;p&gt;下载&lt;a href=&quot;https://github.com/paullinuxthemer/Gnome-OSX&quot;&gt;主题&lt;/a&gt;到&lt;code&gt;~/.themes&lt;/code&gt;, 下载&lt;a href=&quot;https://github.com/keeferrourke/la-capitaine-icon-theme/&quot;&gt;图标&lt;/a&gt;到&lt;code&gt;~/.icons&lt;/code&gt;。
然后在Tweak Tool中设置刚才下载的主题和图标。&lt;/p&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Thu, 08 Feb 2018 19:14:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2018/02/08/customizing-manjaro</guid>
  </item>
  
  <item>
    <title>用火焰图分析Java程序性能</title>
    <link>http://foredoomed.org/blog/2018/02/08/analyze-java-performance-using-flame-graph/</link>
    <description>&lt;p&gt;火焰图是一个非常好的性能分析工具，在火焰图上可以很直观的看到哪个方法执行的时间长，而这个方法就是可以优化的点。在生成火焰图之前需要收集JVM的运行时数据，我用的是一个叫&lt;a href=&quot;https://github.com/jvm-profiling-tools/async-profiler&quot;&gt;async-profiler&lt;/a&gt;的工具。首先下载解压后进入目录执行&lt;code&gt;make&lt;/code&gt;命令，执行完会生成build文件夹。然后执行&lt;code&gt;chmod 777 *&lt;/code&gt;命令，让等会需要执行的文件能够被执行。&lt;/p&gt;

&lt;p&gt;好了，现在开始收集数据。首先执行&lt;code&gt;jcmd&lt;/code&gt;命令找到你要监控的Java程序的进程ID，打个比方&lt;code&gt;1024&lt;/code&gt;。然后执行命令：
&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;./profiler.sh -d 300 -o collapsed -f /tmp/collapsed.txt 1234&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;这个命令的含义是：收集进程ID为1234的程序执行数据300秒，保存到格式为collapsed，文件名为collapsed.txt的文件。等5分钟后，collapsed.txt文件就生成了，有了这个数据文件就可以生成火焰图了。首先下载火焰图工具&lt;a href=&quot;https://github.com/brendangregg/FlameGraph&quot;&gt;FlameGraph&lt;/a&gt;，解压后进入目录并执行命令：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;/flamegraph.pl --colors=java /tmp/collapsed.txt &amp;gt; collapsed.svg&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;等执行完后用浏览器打开collapsed.svg就可以看到火焰图了：
&lt;img src=&quot;http://i1256.photobucket.com/albums/ii494/Foredoomed/flamegraph_zpsjgc5j96j.png&quot; alt=&quot;火焰图&quot;&gt;&lt;/p&gt;

&lt;p&gt;从上图可以看到iBatis的executeSelectKey方法占用了相当长的CPU时间，所以要考虑去掉insert语句里的selectKey标签。&lt;/p&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Thu, 08 Feb 2018 19:14:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2018/02/08/analyze-java-performance-using-flame-graph</guid>
  </item>
  
  <item>
    <title>定制Ubuntu</title>
    <link>http://foredoomed.org/blog/2018/02/07/customizing-ubuntu/</link>
    <description>&lt;h2&gt;0. 安装Flatabulous主题和图标&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo add-apt-repository ppa:noobslab/themes 
$ sudo apt-get update 
$ sudo apt-get install flatabulous-theme

$ sudo add-apt-repository ppa:noobslab/icons 
$ sudo apt-get update 
$ sudo apt-get install ultra-flat-icons&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;1. 安装文泉驿微黑字体&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install fonts-wqy-microhei&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;2. 安装终端字体&lt;/h2&gt;

&lt;p&gt;先从&lt;a href=&quot;https://github.com/powerline/fonts&quot;&gt;这里&lt;/a&gt;下载字体，解压后进入目录执行：
&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ ./install.sh&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;h2&gt;3. 安装浏览器&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install chromium-browser&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;或者&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 
$ sudo gdebi google-chrome-stable_current_amd64.deb&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;4. 安装Flash Player&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install pepperflashplugin-nonfree&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果安装失败，可以使用下面的命令重新安装：
&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo dpkg-reconfigure pepperflashplugin-nonfree&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;h2&gt;5. 安装多媒体解码器&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install ubuntu-restricted-extras&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;6. 安装rar工具&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install unace p7zip-rar sharutils rar arj lunzip lzip&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;7. 安装剪贴板管理器&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install glipper&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;或者&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install clipit&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;8. 修改日期格式&lt;/h2&gt;

&lt;p&gt;修改日期格式为12小时格式显示月份名称、日期和时间。在”使用自定义日期格式”的选框中填入
&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;%B %e, %I:%M %p&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;h2&gt;9. 安装Guake&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install guake&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Guake需要配置，以便在每次登陆时启动。系统设置 &amp;gt; 启动程序，然后点击添加&lt;code&gt;/usr/bin/guake&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;10. 安装unity-tweak-tool&lt;/h2&gt;

&lt;p&gt;用这个工具设置刚才安装的主题，图标，字体等。
&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install unity-tweak-tool&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;h2&gt;11. 安装gnome-tweak-tool&lt;/h2&gt;

&lt;p&gt;用这个工具设置开机启动项。
&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install gnome-tweak-tool&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;h2&gt;12. 安装fish shell&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get install fish&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;13. 清除不必要的包&lt;/h2&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;$ sudo apt-get autoremove&lt;/code&gt;&lt;/pre&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Wed, 07 Feb 2018 19:14:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2018/02/07/customizing-ubuntu</guid>
  </item>
  
  <item>
    <title>JavaScirpt的立即调用函数表达式</title>
    <link>http://foredoomed.org/blog/2014/10/24/immediately-invoked-function-expression/</link>
    <description>&lt;p&gt;说起JavaScript的立即调用的函数表达式(IIFE,Immediately-Invoked Function Expression),随便找一个JS框架或者类库就能看到它的存在。不过，最近在看&lt;a href=&quot;underscorejs.org&quot;&gt;Underscore.js&lt;/a&gt;源代码的时候又发现了一种新的写法，
这马上激起了我的好奇心，所以这次就来好好地研究一下。&lt;/p&gt;

&lt;h2&gt;0. IIFE的写法&lt;/h2&gt;

&lt;p&gt;IIFE的作用就是限制函数和变量的作用域，常见写法有两种：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;// Crockford's preference
(function() {
  console.log('Hello World.');
}());
 
(function() {
  console.log('Hello World.');
})();&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;为什么像这样写法就是IIFE了呢？这是因为JS解释器规定了小括号内的内容必定是表达式，而不可能是函数声明或其他。当然IIFE还可以写成下面这种形式：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;!function(){ console.log('Hello World.'); }();
 
~function(){ console.log('Hello World.'); }();
 
-function(){ console.log('Hello World.'); }();
 
+function(){ console.log('Hello World.'); }();&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;上面这样写法也是IIFE的原因就是：!,~,-,+操作符后只能跟表达式，所以JS解释器就会把这些符号后的JS语句作为表示式处理。&lt;/p&gt;

&lt;p&gt;不过在Underscore.js的源代码中，它的IIFE都不是上面的这些写法，而是写成这样的：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;(function() {
 
}.call(this));&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;那么问题来了，Underscore.js为什么要这么写？要弄清楚这个问题，首先要搞清楚JS的函数调用。&lt;/p&gt;

&lt;h2&gt;1. JavaScirpt的函数调用&lt;/h2&gt;

&lt;p&gt;在&lt;a href=&quot;http://es5.github.io/#x15.3.4.4&quot;&gt;ECMAScript 5.1&lt;/a&gt;规范中，关于函数调用部分是这样描述的：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;15.3.4.4 Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )
When the call method is called on an object func with argument thisArg and optional arguments arg1, arg2 etc, the following steps are taken:&lt;/p&gt;

&lt;p&gt;If IsCallable(func) is false, then throw a TypeError exception.
Let argList be an empty List.
If this method was called with more than one argument then in left to right order starting with arg1 append each argument as the last element of argList
Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and argList as the list of arguments.
The length property of the call method is 1.&lt;/p&gt;

&lt;p&gt;NOTE The thisArg value is passed without modification as the this value. This is a change from Edition 3, where a undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;也就是说当调用函数类型的原型中的call函数时，第一个参数是thisValue，从第二个参数开始才是真正的函数的参数。例如：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;function test(arg) {
  console.log(this + &amp;quot; is not &amp;quot; + arg);
}
 
test.call(&amp;quot;foo&amp;quot;, &amp;quot;bar&amp;quot;) // foo is not bar&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;可以看到，在test函数被调用的时候，this的值被设置成了字符串foo，这也就验证了ECMAScript规范中的说明。讲了这么多有同学可能会有疑问，比如：我们自己调用函数肯定不会像这样调用原型里的call函数，而是直接用函数名加小括号的形式来完成函数的调用，那么call函数跟我们有什么关系呢。
那接下来就来说明这两种调用方式的联系。&lt;/p&gt;

&lt;h2&gt;2. 一般函数调用与call函数的联系&lt;/h2&gt;

&lt;p&gt;我们先来定义一个函数，在这个函数里把this的值打印出来：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;function test() {
  console.log(this);
}
 
test(); // Window&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;有趣的事情发生了，this没有作为参数传入，但是默认设置成了Window对象。联系ECMAScript中关于函数调用的规范，我们可以得到这样的推测：&lt;/p&gt;

&lt;p&gt;在JS解释器执行函数的时候，会把形如function([args...])形式的函数调用转换成形如function.call(Window, [args...])的函数调用。&lt;/p&gt;

&lt;p&gt;通过这样的转换，Window对象自然而然成为了函数默认的this的值。我们已经越来越接近真相了，下面来看一下成员函数中this的值是怎么样的。&lt;/p&gt;

&lt;h2&gt;3. 成员函数中的this&lt;/h2&gt;

&lt;p&gt;同样，首先定义一个类，然后在其中再定义一个成员函数：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;var foo = {
  bar: function(arg) {
    console.log(arg);
    console.log(this);
  }
}&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;执行一下这个bar函数试试：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;foo.bar(&amp;quot;hello world&amp;quot;); // hello world Object&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;可以看到打印出来的this的值是一个Object，而这个Object对象的类型就是foo。那么跟一般函数的转换调用一样，成员函数在被调用的过程中也有一个转换的过程，这个过程就是：&lt;/p&gt;

&lt;p&gt;foo.bar(&amp;quot;hello world&amp;quot;) =&amp;gt; foo.bar.call(foo, &amp;quot;hello world&amp;quot;)&lt;/p&gt;

&lt;p&gt;到这里为止，关于JS函数调用的基础知识已经完备，现在回到本文的开头，来研究一下Underscore.js的IIFE写法。&lt;/p&gt;

&lt;h2&gt;4. Underscore.js的IIFE写法&lt;/h2&gt;

&lt;p&gt;Underscore.js的IIFE是这样写的：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;(function(){
 
}.call(this));&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;这样就显示地指定call函数第一个参数为this，那么这个this的值是什么呢？如果这段代码是在浏览器里执行的话，this就是Window对象。但是如果是在服务器端执行的话，那么这个this就是上下文对象了。直接看代码：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;function Foo() {
  this.foo = true;
 
  (function () {
      console.log(this); // Window
  })();
 
  (function () {
      console.log(this.foo); // undefined
  }());
 
  (function () {
      console.log(this.foo); // true
  }).call(this);
}
 
var foo = new Foo;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;从上面的代码可以看出，这样的写法保证了在IIFE内部引用到的this值是这个IIFE在上下文当中的对象。&lt;/p&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Fri, 24 Oct 2014 21:31:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2014/10/24/immediately-invoked-function-expression</guid>
  </item>
  
  <item>
    <title>下拉刷新TableView</title>
    <link>http://foredoomed.org/blog/2014/03/04/pull-to-refresh-tableview/</link>
    <description>&lt;p&gt;下拉刷新自从被Tweetie创始人洛伦•布里切特(Loren Brichter)发明后，到现在可以说已经成为了TableView的标配功能。而我的RSS阅读器自然也不能例外，所以今天给它加上下拉刷新的功能。&lt;/p&gt;

&lt;p&gt;首先选中TableViewController，然后打开Attribute Inspector面板，把Refreshing设置为Enabled，就像下面这样：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i1256.photobucket.com/albums/ii494/Foredoomed/ScreenShot2014-03-04at111543PM_zps7f02e348.png&quot; alt=&quot;Enable Refreshing&quot;&gt;&lt;/p&gt;

&lt;p&gt;然后修改用来刷新TableView的loadFeed方法：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;- (IBAction)loadFeed {
  [self.refreshControl beginRefreshing];
  AFHTTPRequestOperationManager *manager =
      [AFHTTPRequestOperationManager manager];

  AFHTTPResponseSerializer *responseSerializer =
      [AFHTTPResponseSerializer serializer];

  responseSerializer.acceptableContentTypes =
      [NSSet setWithObjects:@&amp;quot;application/atom+xml&amp;quot;, nil];
  manager.responseSerializer = responseSerializer;

    [manager GET:URL parameters:nil
         success:^(AFHTTPRequestOperation *operation, id responseObject){
      NSData *response = (NSData *)responseObject;
      Feed *feed = [FeedParser parse:response];
      self.feed = feed;

      [self.tableView reloadData];
      [self.refreshControl endRefreshing];
    }
failure:
  ^(AFHTTPRequestOperation * operation, NSError * error) {
    NSLog(@&amp;quot;error: , %@&amp;quot;, error);
  }];
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;与之前相比，在进入loadFeed方法之后就调用&lt;code&gt;[self.refreshControl beginRefreshing]&lt;/code&gt;来显示转动的图片，然后在更新完成后再调用&lt;code&gt;[self.refreshControl endRefreshing]&lt;/code&gt;来隐藏图片。还有就是把方法的返回类型由void变成了IBAction，这样做的目的是为了能够让Refresh Control和loadFeed方法直接关联。所以最后一步只需要在Document Outline中按住Ctrl键，拖动Refresh Control到loadFeed方法上就可以了。&lt;/p&gt;

&lt;p&gt;运行程序看一下效果如何：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i1256.photobucket.com/albums/ii494/Foredoomed/ScreenShot2014-03-04at113613PM_zpsde51fa12.png&quot; alt=&quot;Pull to refresh&quot;&gt;&lt;/p&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Tue, 04 Mar 2014 23:09:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2014/03/04/pull-to-refresh-tableview</guid>
  </item>
  
  <item>
    <title>用AFNetworking为TableView异步加载数据</title>
    <link>http://foredoomed.org/blog/2014/03/01/asynchronously-populate-tableview-with-afnetworking/</link>
    <description>&lt;p&gt;为了让APP有更好的用户体验，所以是不能阻塞主线程的，而RSS的获取和解析都需要一定的时间，所以需要异步地来处理这些工作。&lt;/p&gt;

&lt;p&gt;首先要准备一下UI部分。在stroyboard中，删除项目自动生成的ViewController，重新拖一个TableViewController上去，然后分别创建一个TableViewController类，继承UITableViewController，和TableCell类，继承UITableViewCell。&lt;/p&gt;

&lt;p&gt;在TableViewController.h中定义一个Feed属性：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;#import &amp;lt;UIKit/UIKit.h&amp;gt;
#import &amp;quot;Feed.h&amp;quot;

@interface TableViewController : UITableViewController
@property(nonatomic, retain) Feed *feed;
@end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在TableCell.h中定义一个Label属性：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;#import &amp;lt;UIKit/UIKit.h&amp;gt;

@interface TableCell : UITableViewCell
@property(nonatomic, strong) IBOutlet UILabel *entryLabel;

@end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;把解析RSS的代码放到TableViewController.m中：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;- (void)loadFeed {
  AFHTTPRequestOperationManager *manager =
      [AFHTTPRequestOperationManager manager];

  AFHTTPResponseSerializer *responseSerializer =
      [AFHTTPResponseSerializer serializer];

  responseSerializer.acceptableContentTypes =
      [NSSet setWithObjects:@&amp;quot;application/atom+xml&amp;quot;, nil];
  manager.responseSerializer = responseSerializer;

    [manager GET:URL parameters:nil
         success:^(AFHTTPRequestOperation *operation, id responseObject){
      NSData *response = (NSData *)responseObject;
      Feed *feed = [FeedParser parse:response];
      self.feed = feed;

      [self.tableView reloadData];
    }
failure:
  ^(AFHTTPRequestOperation * operation, NSError * error) {
    NSLog(@&amp;quot;error: , %@&amp;quot;, error);
  }];
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;重写TableView的数据源方法：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

  // Return the number of sections.
  return 1;
}

- (NSInteger)tableView:(UITableView *)tableView
    numberOfRowsInSection:(NSInteger)section {

  // Return the number of rows in the section.
  return self.feed.entries.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  static NSString *CellIdentifier = @&amp;quot;TableCell&amp;quot;;
  TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                                    forIndexPath:indexPath];

  // Configure the cell...

  int row = [indexPath row];
  Entry *entry = [self.feed.entries objectAtIndex:row];
  cell.entryLabel.text = entry.title;

  return cell;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;完成后的TableViewController.m就会是这样的：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;#import &amp;quot;TableViewController.h&amp;quot;
#import &amp;quot;AFNetworking.h&amp;quot;
#import &amp;quot;Feed.h&amp;quot;
#import &amp;quot;FeedParser.h&amp;quot;
#import &amp;quot;Entry.h&amp;quot;
#import &amp;quot;TableCell.h&amp;quot;

@interface TableViewController ()

@end

static NSString *const URL = @&amp;quot;http://v2ex.com/index.xml&amp;quot;;

@implementation TableViewController

- (void)loadFeed {
  AFHTTPRequestOperationManager *manager =
      [AFHTTPRequestOperationManager manager];

  AFHTTPResponseSerializer *responseSerializer =
      [AFHTTPResponseSerializer serializer];

  responseSerializer.acceptableContentTypes =
      [NSSet setWithObjects:@&amp;quot;application/atom+xml&amp;quot;, nil];
  manager.responseSerializer = responseSerializer;

    [manager GET:URL parameters:nil
         success:^(AFHTTPRequestOperation *operation, id responseObject){
      NSData *response = (NSData *)responseObject;
      Feed *feed = [FeedParser parse:response];
      self.feed = feed;

      [self.tableView reloadData];
    }
failure:
  ^(AFHTTPRequestOperation * operation, NSError * error) {
    NSLog(@&amp;quot;error: , %@&amp;quot;, error);
  }];
}

- (id)initWithStyle:(UITableViewStyle)style {
  self = [super initWithStyle:style];
  if (self) {
    // Custom initialization
  }
  return self;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  // Uncomment the following line to preserve selection between presentations.
  // self.clearsSelectionOnViewWillAppear = NO;

  // Uncomment the following line to display an Edit button in the navigation
  // bar for this view controller.
  // self.navigationItem.rightBarButtonItem = self.editButtonItem;

  [self loadFeed];
}

- (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
  // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

  // Return the number of sections.
  return 1;
}

- (NSInteger)tableView:(UITableView *)tableView
    numberOfRowsInSection:(NSInteger)section {

  // Return the number of rows in the section.
  return self.feed.entries.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  static NSString *CellIdentifier = @&amp;quot;TableCell&amp;quot;;
  TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                                    forIndexPath:indexPath];

  // Configure the cell...

  int row = [indexPath row];
  Entry *entry = [self.feed.entries objectAtIndex:row];
  cell.entryLabel.text = entry.title;

  return cell;
}

@end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最后运行看一下结果：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i1256.photobucket.com/albums/ii494/Foredoomed/ScreenShot2014-03-01at123008PM_zps80704577.png&quot; alt=&quot;TableView Example&quot;&gt;&lt;/p&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Sat, 01 Mar 2014 10:58:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2014/03/01/asynchronously-populate-tableview-with-afnetworking</guid>
  </item>
  
  <item>
    <title>Objective-C中的锁及应用</title>
    <link>http://foredoomed.org/blog/2014/02/26/olocks-in-objective-c/</link>
    <description>&lt;p&gt;在多线程编程中，锁是非常重要的工具，而Objective-C提供了好几种不同类型的锁，下面就来看一下这些锁都是怎么用的。&lt;/p&gt;

&lt;h2&gt;0. POSIX Mutex Lock&lt;/h2&gt;

&lt;p&gt;Mutex lock也就是互斥锁，是Unix/Linux平台上提供的一套同步机制。互斥锁提供了三个函数，从函数名就可以知道他们的作用：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;函数&lt;code&gt;pthread_mutex_trylock&lt;/code&gt;和&lt;code&gt;pthread_mutex_lock&lt;/code&gt;的功能完全一致，只不过前者在获取锁失败的情况下会立即返回，而后者则会一直阻塞在那里直到获取到锁为止。互斥锁的使用非常的简单，直接调用上面三个API就可以了：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;pthread_mutex_t mutex;
void MyInitFunction()
{
    pthread_mutex_init(&amp;amp;mutex, NULL);
}
 
void MyLockingFunction()
{
    pthread_mutex_lock(&amp;amp;mutex);
    // Do work.
    pthread_mutex_unlock(&amp;amp;mutex);
}&lt;/code&gt;&lt;/pre&gt;
 

&lt;h2&gt;1. NSLock&lt;/h2&gt;

&lt;p&gt;NSLock类使用的是POSIX线程来实现它的锁操作，而且需要注意的是必须在同一线程内发送unlock消息，否则会发生不确定的情况。NSLock不能被用来实现迭代锁，因为如果发生lock消息两次的话，整个线程将被永久锁住。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;BOOL moreToDo = YES;
NSLock *theLock = [[NSLock alloc] init];
...
while (moreToDo) {
    /* Do another increment of calculation */
    /* until there’s no more to do. */
    if ([theLock tryLock]) {
        /* Update display used by all threads. */
        [theLock unlock];
    }
}&lt;/code&gt;&lt;/pre&gt;
 

&lt;h2&gt;2. @synchronized&lt;/h2&gt;

&lt;p&gt;@synchronized是在Objective-C中最简单方法，只要有个Objective-C对象就可以完成线程同步操作。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;- (void)myMethod:(id)anObj
{
    @synchronized(anObj)
    {
        // Everything between the braces is protected by the @synchronized directive.
    }
}&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;需要注意的是，@synchronized会隐式地添加异常处理代码，也就是当发生异常时会自动释放互斥锁，所以会有一定的性能损耗。&lt;/p&gt;

&lt;h2&gt;3. NSRecursiveLock&lt;/h2&gt;

&lt;p&gt;NSRecursiveLock类定义了可以被同一线程获取多次而不会造成死锁的锁。NSRecursiveLock可以被用在递归调用中，但是只有当多次获取的锁全部释放时，NSRecursiveLock才能被其他线程获取。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];
 
void MyRecursiveFunction(int value)
{
    [theLock lock];
    if (value != 0)
    {
        --value;
        MyRecursiveFunction(value);
    }
    [theLock unlock];
}
 
MyRecursiveFunction(5);&lt;/code&gt;&lt;/pre&gt;
 

&lt;h2&gt;4. NSConditionLock&lt;/h2&gt;

&lt;p&gt;NSConditionLock定义了一个条件互斥锁，也就是当条件成立时就会获取到锁，反之就会释放锁。因为这个特性，条件锁可以被用在有特定顺序的处理流程中，比如生产者-消费者问题。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];
 
// producer
while(true)
{
    [condLock lock];
    /* Add data to the queue. */
    [condLock unlockWithCondition:HAS_DATA];
}
 
// consumer
while (true)
{
    [condLock lockWhenCondition:HAS_DATA];
    /* Remove data from the queue. */
    [condLock unlockWithCondition:(isEmpty ? NO_DATA : HAS_DATA)];
 
    // Process the data locally.
}&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;条件锁的初始状态是&lt;code&gt;NO_DATA&lt;/code&gt;，所以生产者线程在这个时候就会获取到锁，生产完成后再把状态设置为&lt;code&gt;HAS_DATA&lt;/code&gt;；这时消费者线程发现条件变成&lt;code&gt;HAS_DATA&lt;/code&gt;后就可以获取到锁，直到消费结束后再把状态设置成&lt;code&gt;NO_DATA&lt;/code&gt;。&lt;/p&gt;

&lt;h2&gt;5. NSDistributedLock&lt;/h2&gt;

&lt;p&gt;NSDistributedLock是跨进程的分布式锁，底层是用文件系统实现的互斥锁。NSDistributedLock没有实现NSLocking协议，所以没有会阻塞线程的lock方法，取而代之的是非阻塞的tryLock方法。NSDistributedLock只有在锁持有者显式地释放后才会被释放，也就是说当持有锁的应用崩溃后，其他应用就不能访问受保护的共享资源了。&lt;/p&gt;

&lt;h2&gt;6. NSCondition&lt;/h2&gt;

&lt;p&gt;NSCondition类是互斥锁和条件锁的结合体，也就是一个线程在等待信号而阻塞时，可以被另外一个线程唤醒。需要注意的是，由于操作系统实现的差异，即使在代码中没有发送signal消息，线程也有可能被唤醒，所以需要增加谓词变量来保证程序的正确性。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;[cocoaCondition lock];
while (timeToDoWork &amp;lt;= 0)
    [cocoaCondition wait];
 
timeToDoWork--;
 
// Do real work here.
 
[cocoaCondition unlock];&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;在其他线程中唤醒：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;[cocoaCondition lock];
timeToDoWork++;
[cocoaCondition signal];
[cocoaCondition unlock];&lt;/code&gt;&lt;/pre&gt;
 

&lt;h2&gt;7. POSIX Conditions&lt;/h2&gt;

&lt;p&gt;在Unix/Linux平台上也提供了一套条件互斥锁的API：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;// 初始化
int pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *attr);
 
// 等待（会阻塞）
int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mut);
 
// 定时等待
int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mut, const struct timespec *abstime);
 
// 唤醒
int pthread_cond_signal (pthread_cond_t *cond);
 
// 广播唤醒
int pthread_cond_broadcast (pthread_cond_t *cond);
 
// 销毁
int pthread_cond_destroy (pthread_cond_t *cond);&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;和NSCondition类一样，POSIX Conditions也需要和谓词配合使用以确保程序的正确性。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;pthread_mutex_t mutex;
pthread_cond_t condition;
Boolean     ready_to_go = true;
 
void MyCondInitFunction()
{
    pthread_mutex_init(&amp;amp;mutex);
    pthread_cond_init(&amp;amp;condition, NULL);
}
 
void MyWaitOnConditionFunction()
{
    // Lock the mutex.
    pthread_mutex_lock(&amp;amp;mutex);
 
    // If the predicate is already set, then the while loop is bypassed;
    // otherwise, the thread sleeps until the predicate is set.
    while(ready_to_go == false)
    {
        pthread_cond_wait(&amp;amp;condition, &amp;amp;mutex);
    }
 
    // Do work. (The mutex should stay locked.)
 
    // Reset the predicate and release the mutex.
    ready_to_go = false;
    pthread_mutex_unlock(&amp;amp;mutex);
}
 
void SignalThreadUsingCondition()
{
    // At this point, there should be work for the other thread to do.
    pthread_mutex_lock(&amp;amp;mutex);
    ready_to_go = true;
 
    // Signal the other thread to begin work.
    pthread_cond_signal(&amp;amp;condition);
 
    pthread_mutex_unlock(&amp;amp;mutex);
}&lt;/code&gt;&lt;/pre&gt;
 

&lt;h2&gt;参考资料&lt;/h2&gt;

&lt;p&gt;[1] &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/cocoa/conceptual/Multithreading/ThreadSafety/ThreadSafety.html&quot;&gt;Threading Programming Guide&lt;/a&gt;&lt;/p&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Wed, 26 Feb 2014 18:45:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2014/02/26/olocks-in-objective-c</guid>
  </item>
  
  <item>
    <title>Objective-C中Block的实现</title>
    <link>http://foredoomed.org/blog/2014/02/25/objective-c-block-implementation/</link>
    <description>&lt;p&gt;Block是苹果公司在OS X 10.6和iOS 4之后引入的Objective-C语言的扩展。由于Block的出现使得Objective-C拥有了编写类似函数式语言中闭包的能力，现在在许多开源类库中都可以看到Block被用作回调函数的情况。因为Objective-C是用C语言实现的，而C并不原生支持闭包，所以我感兴趣的是Block的底层是怎么实现的。&lt;/p&gt;

&lt;p&gt;在Clang的&lt;a href=&quot;http://clang.llvm.org/docs/Block-ABI-Apple.html&quot;&gt;Block Implementation Specification&lt;/a&gt;文档中可以找到编译后的Block的结构：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;struct Block_literal_1 {
    void *isa; // initialized to &amp;amp;_NSConcreteStackBlock or &amp;amp;_NSConcreteGlobalBlock
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor_1 {
    unsigned long int reserved;         // NULL
        unsigned long int size;         // sizeof(struct Block_literal_1)
        // optional helper functions
        void (*copy_helper)(void *dst, void *src);     // IFF (1&amp;lt;&amp;lt;25)
        void (*dispose_helper)(void *src);             // IFF (1&amp;lt;&amp;lt;25)
        // required ABI.2010.3.16
        const char *signature;                         // IFF (1&amp;lt;&amp;lt;30)
    } *descriptor;
    // imported variables
};&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;可以看到在Block结构体中含有isa指针，这就证明了Block其实就是对象，并具有一般对象的所有功能。这个isa指针被初始化为&lt;code&gt;_NSConcreteStackBlock&lt;/code&gt;或者&lt;code&gt;_NSConcreteGlobalBlock&lt;/code&gt;类的地址。在没有开启ARC的情况下，如果Block中包含有局部变量则isa被初始化为前者，否则就被初始化为后者。而当ARC开启后，如果Block中包含有局部变量则isa被初始化为&lt;code&gt;_NSConcreteMallocBlock&lt;/code&gt;，否则就被初始化为&lt;code&gt;_NSConcreteGlobalBlock&lt;/code&gt;。invoke是一个函数指针，它指向的是Block被转换成函数的地址。最后的imported variables部分是Block需要访问的外部的局部变量，他们在编译就会被拷贝到Block中，这样一来Block就是成为一个闭包了。&lt;/p&gt;

&lt;p&gt;在Clang的文档上有个Block的例子：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;^ { printf(&amp;quot;hello world\n&amp;quot;); }&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;上面这个Block会被编译成：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;struct __block_literal_1 {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(struct __block_literal_1 *);
    struct __block_descriptor_1 *descriptor;
};
 
void __block_invoke_1(struct __block_literal_1 *_block) {
    printf(&amp;quot;hello world\n&amp;quot;);
}
 
static struct __block_descriptor_1 {
    unsigned long int reserved;
    unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 };&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;最终Block就会变成：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;struct __block_literal_1 _block_literal = {
     &amp;amp;_NSConcreteStackBlock,
     (1&amp;lt;&amp;lt;29), &amp;lt;uninitialized&amp;gt;,
     __block_invoke_1,
     &amp;amp;__block_descriptor_1
};&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;参考资料&lt;/h2&gt;

&lt;p&gt;[1] &lt;a href=&quot;http://en.wikipedia.org/wiki/Objective-C&quot;&gt;Objective-C Wiki&lt;/a&gt;&lt;br&gt;
[2] &lt;a href=&quot;http://clang.llvm.org/docs/Block-ABI-Apple.html&quot;&gt;Block Implementation Specification&lt;/a&gt;&lt;/p&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Tue, 25 Feb 2014 19:36:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2014/02/25/objective-c-block-implementation</guid>
  </item>
  
  <item>
    <title>Objective-C的对象模型</title>
    <link>http://foredoomed.org/blog/2014/02/24/object-modeling-of-objective-c/</link>
    <description>&lt;p&gt;Objective-C是一门面向对象，并且在C的基础上加入了Smalltalk式的消息机制而形成的编程语言，它主要被苹果公司用于开发Mac OS X和iOS操作系统。既然Objective-C是面向对象的编程语言，那么我感兴趣的就是对象在内存中是怎么组织和表示的，消息机制又是怎么实现的。&lt;/p&gt;

&lt;h2&gt;0.NSObject&lt;/h2&gt;

&lt;p&gt;NSObject类和Java中的Object类有点相似，都是所有一切类的父类，也就是根类。那么NSObject又是一个怎样的类呢。打开NSObject.h头文件就可以看到NSObject的源码：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;@interface NSObject &amp;lt;NSObject&amp;gt;
{
    Class isa;
}&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;可以看到NSObject是实现了NSObject protocol的Interface，它里面只包含了一个类型为Class的isa属性。isa是『is a』的意思，连起来就是『is a class』，也就是说这个属性保存了有关类的信息。同样来看一下Class的源码，它被定义在objc.h头文件中：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;typedef struct objc_class *Class;&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;Class是objc&lt;em&gt;class类型，objc&lt;/em&gt;class被定义在objc-class.h：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;struct objc_class {          
    struct objc_class *isa; 
    struct objc_class *super_class; 
    const char *name;       
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars;
 
#if defined(Release3CompatibilityBuild)
    struct objc_method_list *methods;
#else
    struct objc_method_list **methodLists;
#endif
 
    struct objc_cache *cache;
    struct objc_protocol_list *protocols;
};&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;可以看到&lt;code&gt;obj_class&lt;/code&gt;是一个结构体，它包含了所有运行时需要的有关类的信息，包括这个类的父类是什么类，实例变量，方法，协议等。有趣的是，&lt;code&gt;obj_class&lt;/code&gt;中也有一个isa属性，那么它又指向哪里呢？它指向的是一个叫做metaclass的对象，并且类型也是&lt;code&gt;obj_class&lt;/code&gt;。所以实例化一个类会有两个对象：本身和metaclass对象。这样做的目的是把实例方法的信息保存到自己本身的类中，而把类方法保存到metaclass类里。那么metaclass中的isa指向哪里呢？因为metaclass类是没有metaclass方法的，所有就不需要再多一个类来保存metaclass类的方法信息，因此，metaclass对象的isa指向自己，形成一个闭环结构。&lt;/p&gt;

&lt;h2&gt;1.消息机制&lt;/h2&gt;

&lt;p&gt;在Objective-C中，方法的调用和其他面向对象语言(例如Java)有点区别。在Java中的方法调用可以写成一般形式为：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;object.method(argument);&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;但是在Objective-C里要这样写：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;[object method:argument];&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;两者的区别是：Java的方法调用是直接调用实例对象的方法，而Objective-C则是发送消息一个消息。发送消息的目标在编译时是不知道的，而是在运行时决定。方法是由selector或者SEL确定的，也就是表示方法名的字符串。消息的接收对象不能保证一定会返回结果，当这种情况发生时就会抛出异常。&lt;/p&gt;

&lt;p&gt;编译器会把发送消息的语句&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;[receiver message]&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;转换为：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;objc_msgSend(receiver, selector, arg1, arg2, ...)&lt;/code&gt;&lt;/pre&gt;
 

&lt;p&gt;在objc_msgSend方法中做的是通过receiver和selector找到要调用的方法，这个方法的类型是IMP型的，然后就可以执行这个方法并把返回值返回出去。这里的IMP类型就是要调用方法的C语言实现，也就是一个C函数指针。&lt;/p&gt;

&lt;h2&gt;2.id&lt;/h2&gt;

&lt;p&gt;id被定义在objc.h中：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;typedef struct objc_object {
    Class isa;
} *id;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到id就是objc_object结构体，它包含了一个isa指针指向类的描述信息，这样的话id就可以用来动态描述类的类型了。&lt;/p&gt;

&lt;p&gt;id的作用类似于Javascript中的var，也就是说用id关键字声明的变量在编译时并不知道其具体类型，而是在运行时决定。因为有id关键字的存在，所以Objective-C就不是单纯的面向对象语言，而是面向对象语言和动态语言的混合体，从这点来看Objective-C倒跟C#有点像。&lt;/p&gt;

&lt;h2&gt;参考资料&lt;/h2&gt;

&lt;p&gt;[1] &lt;a href=&quot;http://en.wikipedia.org/wiki/Objective-C&quot;&gt;Objective-C Wiki&lt;/a&gt;&lt;br&gt;
[2] &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/ObjectModeling/ObjectModeling.html&quot;&gt;Concepts in Objective-C Programming: Object Modeling&lt;/a&gt;&lt;br&gt;
[3] &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/cocoa/conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.html&quot;&gt;Objective-C Runtime Programming Guide&lt;/a&gt;&lt;/p&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Mon, 24 Feb 2014 19:49:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2014/02/24/object-modeling-of-objective-c</guid>
  </item>
  
  <item>
    <title>初试AFNetworking</title>
    <link>http://foredoomed.org/blog/2014/02/23/http-operation-with-afnetworking/</link>
    <description>&lt;p&gt;RSS还是要通过发送网络请求来获取的，Objective-C中的NSURLConnection类可以完成对网络的请求处理。但是还有一个更方便好用的开源网络库：&lt;a href=&quot;http://afnetworking.com/&quot;&gt;AFNetworking&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;首先创建一个RSSService类，然后再定义一个getRSS方法：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;//
//  RSSService.h
//  vot
//
//  Created by Foredoomed on 2/23/14.
//  Copyright (c) 2014 Foredoomed. All rights reserved.
//

#import &amp;lt;Foundation/Foundation.h&amp;gt;

@class Feed;

@interface RSSService : NSObject

- (void *)getRSS;

@end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在实现类中用AFHTTPRequestOperationManager这个类发送GET请求：&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;//
//  RSSService.m
//  vot
//
//  Created by Foredoomed on 2/23/14.
//  Copyright (c) 2014 Foredoomed. All rights reserved.
//

#import &amp;quot;NetWorkService.h&amp;quot;
#import &amp;quot;AFNetworking.h&amp;quot;
#import &amp;quot;Feed.h&amp;quot;
#import &amp;quot;FeedParser.h&amp;quot;
#import &amp;quot;Entry.h&amp;quot;

static NSString *const URL = @&amp;quot;http://v2ex.com/index.xml&amp;quot;;

@implementation RSSService

- (void)getRSS {
  AFHTTPRequestOperationManager *manager =
      [AFHTTPRequestOperationManager manager];

  AFHTTPResponseSerializer *responseSerializer =
      [AFHTTPResponseSerializer serializer];

  responseSerializer.acceptableContentTypes =
      [NSSet setWithObjects:@&amp;quot;application/atom+xml&amp;quot;, nil];
  manager.responseSerializer = responseSerializer;

  [manager GET:URL parameters:nil
  success:^(AFHTTPRequestOperation *operation, id responseObject){
      NSData *data = (NSData *)responseObject;
      Feed *feed = [FeedParser parse:data];

      if (feed != nil) {
        for (Entry *entry in feed.entries) {
          NSLog(@&amp;quot;%@&amp;quot;, entry.title);
        }
      }
    }
  failure:^(AFHTTPRequestOperation * operation, NSError * error) {
    NSLog(@&amp;quot;error: , %@&amp;quot;, error);
  }];
}

@end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里，AFHTTPRequestOperationManager发送的是异步请求，所以block中的代码执行会有时间差，这就好比Javascript中回调函数的存在。从试用的结果来看，AFNetworking对网络操作非常方便，以后再试试别的功能。&lt;/p&gt;
</description>
    <author>mc.liuxuan@gmail.com (Foredoomed)</author>
    <pubDate>Sun, 23 Feb 2014 20:24:00 +0800</pubDate>
    <guid>http://foredoomed.org/blog/2014/02/23/http-operation-with-afnetworking</guid>
  </item>
  
</channel>

</rss>
