不会开机的男孩

Plan

| Comments

不知不觉又是一年,又大了一岁,呵呵,说的很假,因为自己并没有真正的意识到自己又大了一岁,甚至自己现在的年龄都不能一口说出来,过去的一年,甚至之前,我都不能准确的说出我自己到底做了什么,混沌,浑浑噩噩的一生,没有目标,一切都是随心,一切都是随心而发,没有目的,达成不达成,似乎都不重要。那么自己心里到底有什么在乎的了?不知道,那么还有什么感兴趣的呢?

庄子是我最佩服的人,千年前的古人,都可以去猜测天道,追逐天地之本,而做为现代人的我,从小都希望自己能够成为其中的一员,哪怕只是能够感知到一点,为此沉沦数学,物理。

什么是天道,天道不以人类意志左右,甚至和普通人意志相反。而这也就造就了普通人永远无法理解天道。所以,我从来没有觉得自己是普通人,甚至乐于反着做。而今天,我觉得,我错了,因为我现在自己都不了解,原来追求的东西,随着时间的打磨,已经逐渐淡去。现在做的,只是随心而动,追求自己内心的想法——每件事情,比别人多做一点,多深入一点,至于是什么事情,别人的看法,已经不重要了,我发现,我这个理科生,居然是一个彻头彻尾的唯心主义者。

人的一生是要不断学习的。这里面的动力很简单:因为我们在有些方面还“无知”, 无知是做事情的一个障碍。我们如果想做好事情,就要求知,要改变这种无知的状况。而对于创业这件事情,也是我这20多年来,做的最大的一件事情,1年前,对于创业,我还是处在,拿着无知当无畏的状态,而且,现在也没有好多少,但是,我很感谢我们这个Team,包容了我很多缺点,替我遮挡了许多细枝末节,使得我还有时间有精力追求自己内心的想法,而且我相信,我最终一定能够成功,但是这里面的代价实在是太大了,我甚至不能确定,而且害怕,这个时间太长,而那些身边默默支持我的人已经离去,甚至永远看不到了。

我最讨厌的人,就是浪费时间的人,因为,我自己已经浪费了自己20多年的青春。所以,当我在大三的时候,我就已经意识到,自己需要改变这一点——痛恨那些走在我前面档我走路的人,浪费我时间的人。

而现在,我发现,挡在我前面的那个人,不是别人,就是自己。自己的惰性,侥幸心里,成功考验的不仅是智力,更是意志。就像处在激发态的原子,时间会不断地侵蚀他的能量,而如果想要挣脱枷锁,只能是不断地更快地吸取更多的能量。就像鲲鹏,如果沉迷于大海,永远不可能越出水面,飞翔在空中。

呼呼,扯了好多,看看我这一年做了什么,1年前是离毕业还有半年时。

我很庆幸,因为,在很多人不知道自己以后应该做什么时,我知道了我该做什么,计算机就是为我而生的科学,我也很庆幸,我在离开大学的最后半年里,我能够把大学中学到的和没有学到的东西,捏合到了一起,明白了大学这些课程讲述的意义,汇编程序设计,计算机体系结构,编译原理等等耳熟能详的课程捏到一起,虽然不能融会贯通,但是计算机知识体系已经能够较为清晰的展现在脑海里,而这,也就是为什么我放弃考研的原因之一,不需要再学太多的理论来夯实基础,因为我不是要成为科学家,这些理论知识对现在的我来说已经足够,贪多嚼不烂。而更为重要的是,移动互联网,这一波已经滚滚而来,已经不可能在等我3年,就像我大二时,第一次用到智能手机时(Symbian不算)的感触,传统的PC应用已经不可能吸引我,除了mobile。

大学最后的半年,是在创业公司渡过的,第一次自己独立做项目(自己的毕设),而且是一个会正式发布的产品,对于我这样的一个二流大学毕业生来说已经不易。而后的毕业答辩,更是验证了我对学校的不屑,只能挑挑排版错误的导师,充满各种潜规则的评分,对我来说已经没有任何意义,90分和60分,同样没有区别。我唯一在意的是,最后半年,C++的基础打的更扎实了一点,windows消息机制的了解也更深入了一点。也不枉我在这里学习了将近1年的时间。

后半年,风雨突变,windows mobile 已经死在了IOS 和android 的车轮之下,顺应天意,转战IOS。

从0开始学习一个新的语言,新的平台,到产品上线,呵呵,虽然在Appstore 很惨淡,但是,我们并没有放弃,不说了,来年新产品上线再说,不信这个邪了。

总结之后,就要规划,虽然我实在是不想做这个规划,因为实在是不靠谱。1年的时间,说长不长,说短不短。不求别的,只求不浪费时间,全力学习,深入IOS 一点。

转 从无知到有知

| Comments

人的一生是要不断学习的。这里面的动力很简单:因为我们在有些方面还“无知”, 无知是做事情的一个障碍。我们如果想做好事情,就要求知,要改变这种无知的状况。

可是大多数人不知道的是,“无知” (ignorance) 其实不是一个状态,而是两个截然不同的状态,一种叫做不知道型无知 (uninformed ignorance),另一种叫做知道型无知 (informed ignorance)。 相信很多人都有这个体会:某天看到一本书,一篇文章,觉得这里面的学问知识,是自己从来没有想过或者接触过的,是一个崭新的领域,这就代表了你突然发现了自己的无知,而且知道自己的这种无知,也就是,从 uninformed ignorance 跨入了 informed ignorance. 这两种无知的另一个不同在于,第一种无知可以让人无知无畏,因为自己不会认识到这种无知。第二种反而让人小心翼翼,知道自己不懂这方面的知识,或者咨询专业人士,或者恶补相关的知识。我们人生下来,所有的知识都在脑袋的外部,所以,我们最初处于一个纯粹的 uninformed ignorance 状态, 所以,从无知到有知,必然要经过两个过程,第一个过程是从第一种无知变到第二种无知;第二种是消灭部分的第二类无知,达到部分有知。 这两个过程其实截然不同,但是实际上我们常常把他们混淆。

第一个过程其实是非常轻松愉快的过程,甚至不需要花太多的力气。有句话叫见多识广,就是说游山玩水也能增广见识。 在互联网发达的今天,随便点几个链接,随便查几个维基百科,都能够让人获得“增长见闻”的感觉。 这是一个好事,因为我们更加容易的发现自己的无知。 同时,在这个过程里也很容易有认知满足感。 所以,很多人不知不觉的觉得每天只要“增广见闻”就行了,轻松愉快又每天都有新的见闻输入,是多么美好的事情呀。不幸的是,这个过程至多只能让人 informed, 而不能让人 knowledgeable。 想要 knowledge, 绕不过去的是持久的,深入的,有系统的学习。更加不幸的是,这个过程是不那么轻松愉快的。

我上高中的时候非常喜欢数学,正好图书馆里面有大学数学书,我就不管看得懂看不懂都借来看,看着那些如“微分方程”,“复变函数”之类的名词觉得很欣喜,虽然是不断的发现自己以前的无知,却也觉得学到了新东西,新名词,新概念。可是总所周知,“看”是不需要花费任何脑力的,尤其是从不知道到知道自己不知道这个状态,简直就是所谓的顿悟(由此我也怀疑所谓的顿悟其实可能也是突然间觉得自己是个笨蛋,也就悟了)。 就这样,我一度以为自己在数学上是非常的 knowledgeable 了。 然后我大学上了数学系,我突然发现,高中看的那些书,虽然也看了,也仅仅是知道名词 ( informed ) 而已,真正的数学训练,还是等到我用书中知识做后面习题的时候才开始的,而这个过程才不是轻松愉快呢。 我不知道是不是普遍的情况,就我见到的同学,有很多高中原来很喜欢某个专业的,等到真的选了这个专业,突然就不喜欢了,这也是 be informed 和 be knowledgeable 两种认知过程不一样造成的。 这种两种认知过程,是不管怎么都没法互相替代的。换句话说,如果只想捡便宜果子吃,只做第一步,或者用第一步里面的那些轻松愉快来代替第二步,就想变成有知识的人,是不可能的。

缺少持久,系统和深入的学习,知识结构就会处于半调子的状态。 李笑来老师在学英语的若干文章中都提到精读和查字典的重要性。比如说,如果在学英语中满足于 informed ignorance, 遇到不认识的单词仅仅是猜一个意思,也不记下这个单词的用法的话,这个单词还是不能成为自己的词汇。然后,如果仅仅是记下用法,而不在以后有意识的练习使用(或者多次再见到)这个词的话,或许很快也就忘掉了。我们对学语言要系统的精耕细作很同意,但是未必能体会到所有其他学科都需要如此,尤其是在那些我们认为“简单”或者“零碎”的领域,我们往往像蜜蜂一样,成了不知疲倦的收集者,不断的 be informed, 而忘了 be knowledgeable 的背后,不是收集,而是学习。知道自己无知是一件非常好的事情,不过不要容忍处于 knowledge 和 be informed之间的尴尬处境,要不代理给专业人士,要不,抓紧时间学习,赶快从无知,到有知。

2011年终总结

| Comments

不知不觉又是一年,又大了一岁,呵呵,说的很假,因为自己并没有真正的意识到自己又大了一岁,甚至自己现在的年龄都不能一口说出来,过去的一年,甚至之前,我都不能准确的说出我自己到底做了什么,混沌,浑浑噩噩的一生,没有目标,一切都是随心,一切都是随心而发,没有目的,达成不达成,似乎都不重要。那么自己心里到底有什么在乎的了?不知道,那么还有什么感兴趣的呢?

庄子是我最佩服的人,千年前的古人,都可以去猜测天道,追逐天地之本,而做为现代人的我,从小都希望自己能够成为其中的一员,哪怕只是能够感知到一点,为此沉沦数学,物理。

什么是天道,天道不以人类意志左右,甚至和普通人意志相反。而这也就造就了普通人永远无法理解天道。所以,我从来没有觉得自己是普通人,甚至乐于反着做。而今天,我觉得,我错了,因为我现在自己都不了解,原来追求的东西,随着时间的打磨,已经逐渐淡去。现在做的,只是随心而动,追求自己内心的想法——每件事情,比别人多做一点,多深入一点,至于是什么事情,别人的看法,已经不重要了,我发现,我这个理科生,居然是一个彻头彻尾的唯心主义者。

人的一生是要不断学习的。这里面的动力很简单:因为我们在有些方面还“无知”, 无知是做事情的一个障碍。我们如果想做好事情,就要求知,要改变这种无知的状况。而对于创业这件事情,也是我这20多年来,做的最大的一件事情,1年前,对于创业,我还是处在,拿着无知当无畏的状态,而且,现在也没有好多少,但是,我很感谢我们这个Team,包容了我很多缺点,替我遮挡了许多细枝末节,使得我还有时间有精力追求自己内心的想法,而且我相信,我最终一定能够成功,但是这里面的代价实在是太大了,我甚至不能确定,而且害怕,这个时间太长,而那些身边默默支持我的人已经离去,甚至永远看不到了。

我最讨厌的人,就是浪费时间的人,因为,我自己已经浪费了自己20多年的青春。所以,当我在大三的时候,我就已经意识到,自己需要改变这一点——痛恨那些走在我前面档我走路的人,浪费我时间的人。

而现在,我发现,挡在我前面的那个人,不是别人,就是自己。自己的惰性,侥幸心里,成功考验的不仅是智力,更是意志。就像处在激发态的原子,时间会不断地侵蚀他的能量,而如果想要挣脱枷锁,只能是不断地更快地吸取更多的能量。就像鲲鹏,如果沉迷于大海,永远不可能越出水面,飞翔在空中。

呼呼,扯了好多,看看我这一年做了什么,1年前是离毕业还有半年时。

我很庆幸,因为,在很多人不知道自己以后应该做什么时,我知道了我该做什么,计算机就是为我而生的科学,我也很庆幸,我在离开大学的最后半年里,我能够把大学中学到的和没有学到的东西,捏合到了一起,明白了大学这些课程讲述的意义,汇编程序设计,计算机体系结构,编译原理等等耳熟能详的课程捏到一起,虽然不能融会贯通,但是计算机知识体系已经能够较为清晰的展现在脑海里,而这,也就是为什么我放弃考研的原因之一,不需要再学太多的理论来夯实基础,因为我不是要成为科学家,这些理论知识对现在的我来说已经足够,贪多嚼不烂。而更为重要的是,移动互联网,这一波已经滚滚而来,已经不可能在等我3年,就像我大二时,第一次用到智能手机时(Symbian不算)的感触,传统的PC应用已经不可能吸引我,除了mobile。

大学最后的半年,是在创业公司渡过的,第一次自己独立做项目(自己的毕设),而且是一个会正式发布的产品,对于我这样的一个二流大学毕业生来说已经不易。而后的毕业答辩,更是验证了我对学校的不屑,只能挑挑排版错误的导师,充满各种潜规则的评分,对我来说已经没有任何意义,90分和60分,同样没有区别。我唯一在意的是,最后半年,C++的基础打的更扎实了一点,windows消息机制的了解也更深入了一点。也不枉我在这里学习了将近1年的时间。

后半年,风雨突变,windows mobile 已经死在了IOS 和android 的车轮之下,顺应天意,转战IOS。

从0开始学习一个新的语言,新的平台,到产品上线,呵呵,虽然在Appstore 很惨淡,但是,我们并没有放弃,不说了,来年新产品上线再说,不信这个邪了。

总结之后,就要规划,虽然我实在是不想做这个规划,因为实在是不靠谱。1年的时间,说长不长,说短不短。不求别的,只求不浪费时间,全力学习,深入IOS 一点。

Objective-C 一些很基础的总结

| Comments

学习 Objective-C大概4个月了,居然给一个还没毕业的家伙吹了吹,呼,希望不要误人子弟。这里总结一下,毕竟这是第一次完整的讲一个东西。

附上PPTObjective-C Primary 。资源99%来自WWDC 2010 session 113。

Common Concepts

Objective-C 相对其他更了解的C++语言来说,还是有些不同的。如下表

alt text

这里面有几点比较重要

  • Objective-C 中所有的类,其实是另一种“类”的对象,所以Objective-C 中的类方法,其实是另一种类的实例方法。 Objective-C Message
  • Objective-C 中没有静态变量,都是用全局变量实现的。

Category

如何给一个类增加一个函数方法,在C++中是不可能的(或是很难)但是在Objective-C中确实很简单的事情,category 做的就是这件事情。

当第一次看到category 时,我几乎肯定这是一个非常坑爹的设计,因为这个可以完美的覆盖原有类的方法,如果使用不当,绝对是灾难性的错误。但是,随着使用时间变长category 的好处也慢慢体会出来。

  • 给系统原有的类或是第三方的类增加函数,而不用使用一个新的类,这样使用会更加方便,特别是使用IB时,不需要将系统的类换成自己定义的类,这样减少了非常多的移植问题和同步工作。 当然,如果使用不当,也会遇到问题

  • 函数覆盖问题,之前提到过

  • 增加大量的category 会降低系统性能,特别是如果大量的加到一些基础类上,如NSObject 等,因为,几乎整个系统都在使用这些类,而过多的category,不仅降低自己代码的效率,也会降低framework代码的效率,这里的效率,应该主要在类初始化上,和消息发送上面。

SEL

Memory Management

语言是离不开平台的,而内存管理,则是了解平台中最基础的部分。而cocoa touch 的内存设计也就是基于引用计数的设计,是针对很早以前的设备设计,显然不适合现在的硬件设备。但是,现在我们似乎没有其他的选择,在一开始学习时。

基于引用计数的内存管理,设计的本质其实就是一个DAG(有向无回图)

alt text

对于引用计数的内存管理,这一点实在是不陌生,不管是什么语言,都会遇到一个问题,循环引用

alt text

当形成回路时,循环引用发生,导致内存泄露。而对应的方法,不管是什么语言,都需要把引用分为强引用和弱引用

alt text

解决引用循环的方法很多,但是实质上,都是通过抽象成父子关系来做,一个强引用,一个弱引用,图形下方的节点通过弱引用连接上面的节点,图形上方的节点,通过强引用连接下方节点。实例就是delegate,属性被声明为assign

Autorelease Pools

autorelease 应该是初学者最容易糊涂的地方,一开始我也非常害怕使用Autorelease 变量,因为,这些变量不仅会增大内存开销,而且使用不当,crash的位置就是main函数,调试器几乎没有任何帮助,但是仍然有非常多的framework是基于autorelease 变量的,所以还是需要屡屡。

cocoa touch 是事件驱动的,我们通过接受一个个的event来跑我们的程序,那么简单的讲,就是一个while的死循环,不断地获取一个event,处理一个event。

alt text

处理event的时候,framework 帮我们建立了一个autorelease pool。

alt text

当我们处理或是叫响应一个event时,比如调用了[NSDate date] 函数,这个函数,返回了一个autorelease 变量d

而这个变量,事实上是被autorelease pool 所引用。

alt text

当一层层stack pop 之后,我们可以看到 autorelease 变量的生命周期

alt text

alt text

当调用[pool drain]后,autorelease pool 随之消失,伴随着还有那个var d,回到原点,在下一个event cycle

alt text

Objective C SEL

| Comments

上一篇《Objective-C Message》,总结了一点关于Objective-C 消息发送中有意思的东西,中间穿插了一点关于SEL有趣的东西,之前,我们知道Objective-C runtime 在处理selector时,是做一个unique hash set, 那么今天,我们看看这个set 是如何产生的。这篇文章参考了link

unique set的好处是,字符串的比较可以非常迅速,但是也带来一个棘手的问题,创建一个这样的集合,真的不容易。虽然我们能够在compiler和 link的时候保证我们程序中唯一,但是这还远远不够,因为我们并不是生活在真空中,我们的程序需要和各种各样的其他程序协同工作,那么如何能够在这种繁杂的各种情况下,保证唯一呢?

简单说,就是在程序A中,有一个@selector(customInit),但在程序A中引入了程序B,而B中也有一个@selector(customInit),那么,显然,我们需要修正这2个selector,使他们指向同一个内存地址,这样才能保证消息发送正确。

好吧,我们程序员又要惊呼了,这是一个非常非常大的开销,因为

1、我们只能在运行时做这些工作。

2、这些工作是不可能不绕过strcmp(创建hash表时,如果发生了冲突,我们为了保证绝对正确,只能strcmp)。

3、当我们修正之后,也意味着,我们浪费了空间,而实际上就是我们创建了一个更大的hashtable(元素越多,发生碰撞的概率越大,空间的开销越大),

4、代码段在被映射到内存地址空间时,都在可读地址空间上,那么修正,意味着我们又多做了copy-on-write,同样意味着更多的空间开销

5、事实上,这样的函数还非常多,那些界面库函数等等,几乎被所有app引用 e.g. init,initWithFrame:。

更多的空间,更多的比较,导致了性能下降,特别是在程序载入时。事实上,runtime 和os 为我们的selector unique 做了下面的优化,大体可以理解成2个部分

1、减少需要修正的selector 集合

之前,我们看到的只有一个hash set,在runtime 载入时创建,但是,现在我们有了2个set(这个set是在Snow Leopard被加入的)。

一个是之前我们知道的,另一个也是一个hash set 当然,特别的是,这是一个perfect hash set。

从之前的5条件中,我们知道了,这些常用的如系统库函数,cocoa.framework中的selector 几乎被所有app引用,而且,我们非常开心的看到了,这些函数,都是可以确定的固定集合。事实上,dyld(dynamic loader and linker),给我们build了一个dyld shared cache,而且是一个perfect hash。而这个被映射到了各种app内存地址空间,并被共享。当我们创建unique selector set 时,我们可以先查找这个perfect hash set,来判断,我们是不是需要动态扩展我们的程序自己的selector hash set。而且,由于是perfect hash,使我们能够拥有在最坏情况下常数时间的开销。

2、延迟加载

对于这个,我们已经不陌生了,不管是windows dll 中的延时加载,还是各种在linux中的动态模块的延时载入,原理都是一样的。这些工作,只有在认为是必要条件时,才被真正的加载并初始化。

说的实在是太空了,让我们来看代码吧。

当类被调用或是说在被发送消息之前,类,需要被初始化一下,做的工作就是一些,运行时必要的空间分配,初始化,修正selector,methodlist, propertylist,categorylist等等的工作,我们这里,只是关注selector部分。

prepareForMethodLookup->realizeClass –> methodizeClass->attachMethodLists->fixupMethodList.

经过一系列的东东,修正我们的methodlist时,我们需要将methodlist中的SEL 修正,而这个过程就是我们关注的select unique。

不知道,大家还记得不记得,上一篇讲的 method结构

typedef struct method_list_t {

uint32_t entsize_NEVER_USE;  // low 2 bits used for fixup markers

uint32_t count;

struct method_t first;

} method_list_t;

typedef struct method_t {

SEL name;

const char *types;

IMP imp;

} method_t




static void 
fixupMethodList(method_list_t *mlist, BOOL bundleCopy) 
{ 
    assert(!isMethodListFixedUp(mlist));

    // fixme lock less in attachMethodLists ? 
    sel_lock();

    uint32_t m; 
    for (m = 0; m < mlist->count; m++) {

        //studentdeng note:fixup selector and make sure selector unique 
        method_t *meth = method_list_nth(mlist, m); 
        SEL sel = sel_registerNameNoLock((const char *)meth->name, bundleCopy); 
        meth->name = sel;

        if (sel == (SEL)kIgnore) { 
            meth->imp = (IMP)&_objc_ignored_method; 
        } 
    }

    sel_unlock();

    setMethodListFixedUp(mlist); 
}






sel_registerNameNoLock->__sel_registerName


static SEL __sel_registerName(const char *name, int lock, int copy) 
{ 
    SEL result = 0;

    if (lock) rwlock_assert_unlocked(&selLock); 
    else rwlock_assert_writing(&selLock);

    if (!name) return (SEL)0; 
    result = _objc_search_builtins(name); //studentdeng note:这里就是查找perfect hash set build by dyld cache 
    if (result) return result; 

    if (lock) rwlock_read(&selLock); 
    if (_objc_selectors) { 
        result = __objc_sel_set_get(_objc_selectors, (SEL)name); //studentdeng note: 这里就是查找我们程序自己的hash set 
    } 
    if (lock) rwlock_unlock_read(&selLock); 
    if (result) return result;

    // No match. Insert.

    if (lock) rwlock_write(&selLock);

    if (!_objc_selectors) { 
        _objc_selectors = __objc_sel_set_create(NUM_NONBUILTIN_SELS); 
    } 
    if (lock) { 
        // Rescan in case it was added while we dropped the lock 
        result = __objc_sel_set_get(_objc_selectors, (SEL)name); 
    } 
    if (!result) { 
        result = (SEL)(copy ? _strdup_internal(name) : name); 
        __objc_sel_set_add(_objc_selectors, result); 
#if defined(DUMP_UNKNOWN_SELECTORS) 
        printf("\t\"%s\",\n", name); 
#endif 
    }

    if (lock) rwlock_unlock_write(&selLock); 
    return result; 
}

牛b的代码,从来都是自解释的。