Sunday, November 1, 2009

程序员修炼之道(1-7)

http://blog.csdn.net/Mac_cm/archive/2009/10/28/4738102.aspx

十个糟糕的程序员的行为

原文:http://cocre.com/?p=1081

之前本站发表过《优秀程序员的十个习惯》以及《程序员需要具备的基本技能》,那是我们需要去学习和培养的。这里,我们主要讨论十个糟糕程序员的特征,主要是需要让我们去避免和小心的。

1) 情绪化的思维

如果你开始使用不同颜色的眼光来看待这个世界的话,那么你可能会成为一个很糟糕的程序员。情绪化的思维或态度很有可能会把自己变成一个怪物。相信你经常可以看到很多很糟糕的程序会使用下面的这些语句:

  • 我的程序不可能有这种问题。
  • Java就是shit。
  • 我最恨的就是使用UML做设计。
  • 需求怎么老在变,没办干了。
  • 受不了这些人,他们到底懂不懂啊。
  • …… ……

这些带着情绪化的思维和态度,不但可以让你成为一个很糟糕的程序员,甚至可以影响你的前途。因为,情绪化通常都是魔鬼,会让你做出错误的判断和决定,错误码率的判断和决定直接决定了你的人生。

2) 怀疑别人

糟糕的程序总是说:“我的代码一定是正确的,我怀疑编译器有问题”,“我这应该没有问题吧,STL库怎么这么难用啊”。我曾经见过有程序员这样使用 STL类:map,当他发现这样放入字符串后却取不出来,觉得那是STL库的BUG,然后自己写了一个map!我的天啊!

某些时候,过早的下结论是一个很不好的习惯,任何事情都有其原因,只有知道了原因,你才能知道是谁的问题。一般来说,总是自己出的问题。

3) 过多关注实现,陷入问题细节

有些时候,当我们面对一个问题或是一个需求的时候,糟糕的程序员总是会马上去找一个解决方案或是实现,这是一个很不好的习惯。设计模式告诉我们,“喜欢接口,而不是实现”就是告诉我们,认清问题的本质和特性要比如何实现更重要。

  • 对于一个客户的问题来说,首先应该想到的是如何先让用户正常工作,如何恢复正在“流血”的系统,而不是把用户放在一边而去分析问题的原因和解决方案。
  • 对于解决一个bug来说,重现bug,了解原来程序的意图是首先重要的事,而不是马上去修改代码,否则必然会引入更多的BUG。
  • 对于一个需求来说,我们需要了解的需求后面的商业背景,use case和真实意图,而不是去讨论如何实现。只有了解了用户的真实意图,实际使用的方式和案例,你才能真正如果去做设计。

糟糕的程序总是容易陷入细节,争论于如何实现和实现难题,以及问题的根本原因,而忽略了比这些更重要的东西。只有看懂了整个地图,我们才知道要怎么去走。

4) 使用并不熟悉的代码

糟糕的程序员最好的朋友是 Ctrl-C 和 Ctrl-V ,有些时候,他们并不知道代码的确切含义,就开始使用它,有证据表明,由拷贝粘贴引发的bug占了绝大多数。因为,代码总是只能在特定的环境下才能正常地 工作,如果代码的上下文改变了,很有可能使得代码产生很多你不知道的行为,当你连代码都控制不住了,你还能编出什么好的程序呢?

5) 拼命工作而不是聪明的工作

对于糟糕的程序员,我们总是能看到他们拼命地修正他们的bug,总是花非常多时间并重复地完成某一工作。而好的程序可能会花双倍的时间来准备一个有 效的开发环境,工具,以及在开发的时候花双倍甚至10倍的时间来避免一些错误。好的程序员总是会利用一切工具或手段来让自己的工作变得更有效率,总是为在 开发的时候尽可能得不出错。后期出错的成本将会是巨大的,而且那时改正错误的压力也是巨大的。所以,糟糕的程序通常会让自己进入一种恶性循环,他们看上去 总是疲惫的,总是很辛苦的,所以更没有时间来改善,越没有时间来改善,就有越多的问题。所以,拼命工作有些时候可能表明你不是一个好的程序员。

6) 总是在等待、找借口以及抱怨

当需求不明确的时候,当环境不是很满意的时候,他们总是在等待别人的改善。出现问题的时候,总是在找借口,或是抱怨这也不好,那也不好,所以自己当 然就没有做好。糟糕的程序员总是希望自己的所处的环境是最好的,有明确的需求,有非常不错的开发环境,有足够的时间,有不错的QA,还有很强的team leader,以及体贴自己的经理,有足够的培训,有良好的讨论,有别人强有力的支持……,这是一种“饭来张口,衣来伸手”的态度,这个世界本来就不完 美,一个团队需要所有人去奋斗,况且,如果什么都变得完美了,那么,你的价值何在吗?driving instead of waiting, leading instead of following.

7) 滋生办公室政治

有句话叫“丑女多作怪”,意思是说如果一个自己没有真实的能力的话,那么他一定会在其它方面作文章。糟糕的程序员也是这样,如果他们程序编不好的 话,比不过别人的话,他们通常会去靠指责别人,推脱责任,或是排挤有能力的人,等等不正常的手段来保全自己。所以,糟糕的程序通常伴随着办公室政治。

8 ) 说得多做得少

糟糕的程序员总是觉得自己什么都懂,他们并不会觉得自己的认识和知识都是有限的。这就是所谓的夸夸其谈,是的,什么都做不好的程序员能靠什么混日子呢?就是吹啊吹啊。

另一个表现方式是他们在评论起别人的程序或是设计,总是能挑出一堆毛病,但自己的程序写得也很烂。总是批评抱怨,而没有任何有建设性的意见,或是提出可行的解决方案。

这些糟糕的程序员,总是喜欢以批评别人的程序而达到显示自己的优秀。

9) 顽固

当你给出一打证据说明那里有一个更好的方案,那里有一个更好的方向的时候,他们总是会倔强的认为他们自己的做法才是最好的。一个我亲身经历的事例就 是,当我看到一个新来的程序员在解决一个问题的时候走到了错误的方向上时,我提醒他,你可能走错了,应该是另外那边,并且我证明了给他看还有一个更为简单 的方法,有。然而,这位程序员却告诉我,“那是我的方法,我一定要把之走下去,不然我会非常难受”,于是,在三天后的代码评审中,在经过顽固地解释以及一 片质疑声中,他不得不采用了我最先告诉他的那个方法。

这些程序员,从来不会去想,也不会去找人讨论还有没有更好的方法,而是坚持自己的想法,那怕是条死路都一往直前,不撞南墙永不回头。

10) 写“聪明”的代码

他们写出来的代码需要别的同事查看程序语言参考手册,或是其程序的逻辑或是风格看上去相当时髦,但却非常难读。代码本应该简洁和易读,而他们喜欢在代码中表现自己,并尝试另类的东西,以显示自己的才气。是的,只有能力有问题的程序员才需要借助这样的显示。

记得以前的一个经历,一位英语很不错的程序员加入公司,本来对我们这些英语二把刀来说,我们喜欢看到的是简单和易读的英文文档,然后,那位老兄为了 展示他的英语如何牛,使用了很多GRE中比较生僻的短语和词汇。让大家阅读得很艰苦。最有讽刺意味的是,有一位native的美国人后来在其邮件中询问他 某个单词的意思。呵呵。

你是一个糟糕的程序员吗?欢迎你分享你的经历

22条经典的编程引言

原文:http://cocre.com/?p=808 - 酷壳

下面的这些经典的引言来自英文,也许有些我翻译的是不很好,所以,我提供了中英对照,如果有问题,请大家指正。

过早的优化是万恶之源。Premature optimization is the root of all evil!
- Donald Knuth

在水里行走和以一个需求规格进行软件开发,有一点是相同的,那就是如果水或需求都被冻住不 了,那么行走和软件开发都会变得容易。Walking on water and developing software from a specification are easy if both are frozen
- Edward V Berard

Hofstadter 定理:“一件事情总是会花费比你预期更多的时间,就算是你已经考虑过本条Hofstadter 定理”。It always takes longer than you expect, even when you take into account Hofstadter’s Law.
- Hofstadter’s Law

有些遇到问题的人总是会说“我知道,我会使用正则表达式”,那么,你现在有两个问题了。(意思是:你本想用正则表达式来解决你已有问题,但实际上你 又引入了“正则表达式”的一个新问题)Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems
- Jamie Zawinski

调试程序的难度是写代码的两倍。因此,只要你的代码写的尽可能的清楚,那么你在调试代码时就不需要那么地有技巧。Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.
- Brian Kernighan

用代码行来衡量开发进度,无异于用重量来衡量制造飞机的进度。Measuring programming progress by lines of code is like measuring aircraft building progress by weight.
- Bill Gates

PHP被一些不合格的业余人员造就成了一个小恶魔;而Perl则是被一些熟练的但不正当的专业人员造就成了一个超级大恶魔。PHP is a minor evil perpetrated and created by incompetent amateurs, whereas Perl is a great and insidious evil, perpetrated by skilled but perverted professionals.
- Jon Ribbens

在两个场合我被问到:“请你告诉我,如果你给机器输入了错误的数字,那么,是否还能得到正确的答案?”我并不能正确领会这类想法。(注意,本引言的 作者姓Babbage,这个名字和神父同名,意思是,作者在反问提问的人,你是问我还是向神父祈祷?)On two occasions I have been asked, ‘Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?’ I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question.”
- Charles Babbage

在编程的时候,我们一定要想像一下,以后维护我们自己的代码的那个人会成为一个有暴力倾向的疯子,并且,他还知道我们住在哪里?Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
- Rick Osborne

现代的编程是“程序员努力建一个更大更傻的程序”和“世界正在尝试创造更多更傻的人”之间的一种竞赛,目前为止,后者是赢家。 Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.
- Rich Cook

我才不关心我的代码是否能在你的机器上工作!我们不会给你提供机器。I don’t care if it works on your machine! We are not shipping your machine!
- Ovidiu Platon

我总是希望我的电脑能够像电话一样容易使用;我的这个希望正在变成现实,因为我现在已经不知道怎么去使用我的电话了。I have always wished for my computer to be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone.
- Bjarne Stroustrup

计算机是一种在人类历史上所有发明中,可以让你比以前更快地犯更多的错误的发明,同样,其也包括了“手枪”和“龙舌兰酒”这两种发明的缺陷。A computer lets you make more mistakes faster than any other invention in human history, with the possible exceptions of handguns and tequila.
- Mitch Ratcliffe

如果调试程序是一种标准的可以铲除BUG的流程,那么,编程就是把他们放进来的流程。If debugging is the process of removing software bugs, then programming must be the process of putting them in.
- E. W. Dijkstra

教一群被BASIC先入为主的学生,什么是好的编程风格简直是一件不可能的事。对于一些有潜力的程序员,他们所受到的智力上的伤害远远超过了重建他 们的信心。It is practically impossible to teach good programming style to students that have had prior exposure to BASIC. As potential programmers, they are mentally mutilated beyond hope of regeneration.
- E. W. Dijkstra

理论上来说,理论和实际是一样的。但实际上来说,他们则不是。In theory, theory and practice are the same. In practice, they’re not.
- Unknown

只有两个事情是无穷尽的:宇宙和人类的愚蠢。当然,我现在还不能确定宇宙是无穷尽的。Two things are infinite: the universe and human stupidity; and I’m not sure about the universe.
- Albert Einstein

Perl这种语言就好像是被RSA加密算法加密过的一样。Perl - The only language that looks the same before and after RSA encryption.
- Keith Bostic

我爱“最终期限”,我喜欢“嗖嗖嗖”的声音就像他们在飞一样。I love deadlines. I like the whooshing sound they make as they fly by.
- Douglas Adams

说Java好的是因为它跨平台就像好像说肛交好是因为其可以适用于一切性别。Saying that Java is good because it works on all platforms is like saying anal sex is good because it works on all genders
- Unknown

XML就像是一种强暴——如果它不能解决你的问题,那只能说明你没有用好它。XML is like violence - if it doesn’t solve your problems, you are not using enough of it.
- Unknown

爱因期坦说,自然界中的一切一定会有一个简单的解释,因为上帝并不是反复无常和独裁的。当然,不会有什么信仰能程序员像爱因期坦那样感到舒服。 Einstein argued that there must be simplified explanations of nature, because God is not capricious or arbitrary. No such faith comforts the software engineer.
- Fred Brooks

Monday, October 26, 2009

280行代码实现在J2ME中解压缩ZIP文件

http://www.cnjm.net/tech/article4729.html

[轉貼]编程习惯

编程习惯


/Alexey Radul/程显峰

原文地址:http://web.mit.edu/~axch/www/programming_habits.html

近年来,我对编程艺术有很多体会。过后,我发现有些体会是错的;有些体会我遗忘了但又重新感受到;而另外有些则是必然会发现的。我还完善了一套项目管理的好习惯,这习惯包括我自己的,或者小组的抑或是大的,公司内部的。一方面,这些习惯对软件的成功开发是至关重要的(太小或者纯粹巧合的不算),另一方面,这些习惯也不是什么高深莫测的东西,较小的篇幅就可以说清楚了,第三,这些习惯都没有得到应有的重视。所以我把这些写下来,而你呢,正读着呢。

本文包含很多零散的个人建议,有六大块,各讲一个方面。因为建议很多而且相互联系紧密,所以不太好把他们逐条陈列。这样写还有一个好处就是你可以有所挑选的阅读,把你所知道的部分跳过去,把你想重新思考的部分温习一下,或者只是简略的阅读提纲不深入研究具体内容。


1 版本控制

版本控制是一种在开发的过程中对软件开发的历史系统地跟踪的方法。此项任务由版本控制系统完成,如CVSSubversion。版本系统保持了一个受控编码的历史痕迹,提供很多操作:获得当前版本代码(通常称为检出);提交修改;更新工作拷贝来协调他人的修改。版本控制系统还提供一些其他功能,如用不同的方式检查代码的历史,撤销更改,回滚到软件历史的某个点,解决冲突(两个人同时对相同的代码段进行了不同的修改)。

用过文本编辑器的撤销按 钮,或是用备份文件进行过恢复的人,都能体会到让电脑记住以前的东西的惊奇效果。而代码比普通的文件要复杂的多,自然这种功能在开发中就更加重要了。要是 你没有体会过与别人一起开发的乐趣,记住我的话:潜在的混淆和数据的损失是与参与的人数成正比的。因此,版本控制在开发软件的过程中的作用是不可估量的, 如果使用得当的话还会发挥更大的效力。

那么,怎样才能用好版本控制呢?

  1. 选用一个优秀的版本控制系统 我现在非常中意Subversion,它不但高效,而且免费。它现在非常流行,并且会变得更加流行。它几乎不干扰其他开发过程。我并不是说它是完美的,但在你找到更好的之前确实是一个不错的选择。
  2. 一开始就要版本化 要是在项目中有些东西要保存在比草稿纸更加正式一点的地方,那么绝对要将其版本化。推论:要是你已经开始了一个没有版本控制的项目,马上建立一个,并提交项目。
  3. 就算你单干也要版本化 三个星期后的你将大大有别于今天的你。努力实践版本控制使得你实现你的意图的时候非常清晰,要是你忘记了手头做的什么事情(相信我,你会忘的),那它可有大用处了。此外,你还免费的做了一个备份,【1】看来这么做一点损失都没有,好处倒不少。
  4. 只要是人类的智慧就要版本化 代码(肯定是人类的智慧啦),测试用例,编译脚本,文档,任务列表,解释说明,演讲稿,想法,需求—只要是经过人的大脑创造出来的一切,都应该记录在版本控制系统里,除非你有更好的理由将它们放到别处。
  5. 计算机生成的文件就不必了,这样做只能导致项目出现不一致(如有人提交了源文件,却忘记生成了有依赖关系的衍生文件)。比较好的做法是让版本控制 系统忽略这些衍生文件,需要的时候再生成就是了。但是万万要把能衍生文件的人类原创途径记录在案,包括执行生成过程的命令之类的。
  6. 做好日志 好的版本控制系统都会在每一次更改的时候让你留下日志,目的是解释一下你对提交的代码都做了些什么。千万别忽略这一步,一定要写,并且好好的写。

i. 不光是为别人而写也是为自己,认真细致记录日志会迫使你梳理你的设计,看清问题所在,认清正在做的事情,也会使得想知道细节的人(同样包括未来某时的你)与代码的作者有个交流。

ii. 做了什么记下来(必要时补充原因),而不是怎么做的。要是怎么做的真的那么令人感兴趣,而且从修改本身很难去理解,当然有必要记一记,但是通常代码本身已经很能说明怎么做的了。要是真的有什么地方不清楚的话,那一定是你的思路。

iii. 描述点滴所做 版本控制系统能帮助你找到你所做的更改,要试着将所有的修改都详细的告诉系统。推论:不要做自己都解释不清的事情。要将其分割成很多比较小的步骤,然后一个一个的来。


7. 不能搞破坏 每一次你提交了代码,系统应该是好用的。也就是说,其他人此时更新代码后应该能够编译(可能的话),执行测试套件,并通过测试。将错误提交了是对与你协同 的人(还是包括未来的你)极大的不尊重。这会让他们搞不清楚到底是因为自己的问题还是你提交的一些垃圾导致了系统不能运转)。【2】

推论:要是你真的搞破 坏了,要道歉,并立刻修复。

8. 修改要小到原子 理想的情形下,每一次修改只包含一个意图,每条日志只是说明一个问题的单句段落。这有一条傻瓜法则用以判断两个相互联系的事情到底是一个还是两个原子修改:问问自己会不会有人只想撤销其中一个而保留另一个。如果答案是肯定的,就要分开来提交。

9.不要改而不交 拖延修改的提交时间越长,你越容易忘了自己都做了什么,越容易产生BUG,也越容易与其它人的相关工作不协调。要是你没有提交修改,其实一天的活儿就不算干完,除非你有更好的理由。


2 构建系统

构 建系统是很多自动完成软件开发任务。其中最常见的就是编译代码。运行测试组件也是构建系统提供的功能。还有很多其他的功用,像根据代码注释生成可浏览的文 档,将组件合并用以发布,等等。将这些工作自动化可以节省很多时间和人力,还会防止有无误操作或是由于懒惰疏忽而产生的错误。

已经有这样的工具了。UNIX工具make已经成为构建自动化的标准好多年了,而且相当好用。AntJava领域内非常流行,我个人喜欢rake3】。现代IDE也有部分这样的功能,或是有调用这些标准工具的接口。无论你最终使用哪一种工具,编译,测试,或是其它什么别的,应该简单到只是按一下按钮。

构建系统建议:

  1. 使用真正的构建工具 学习一个全新的工具是有些令人却步,但却很值得。简单的脚本总是能搞定你的项目。不会有项目小到不适合应用这些标准工具,只有极少数特大号的项目不适合。【4】
  2. 使一切自动化 编译和测试应该从一开始就精心地自动化了。同样当你开始生成文档或者代码,做清理,安装等等的时候,也要使其自动完成。总的来说,要干第二次的任务最好就要自动化。
  3. 自动过程要明晰 尤其要注意,当大家提交东西的时候,应该有一个精心定义的“构建”,一种大家都不应该破坏的“构建”。通常,这会包括成功的编译结果和测试结果,但是,一定要说清楚哪些命令用来执行,保证其总是能干活。并确保在任意一次执行都能清楚地知道它是否运转正常。


3 自动化的测试套件

测试套件是很多验证代码有效的测试。如果其能够完全由计算机来执行并评估结果,那么就称其为自动化了的。

可以将测试按照测试代码的多少分类:“单元测试检验单一组件的功能,比如一个函数或者一个类。集成测试检验若干组件,也可能是整个系统是否能协同工作。功能测试检验系统(通常是全部或大部分)在一个较高的层次上能否正常运转。后两个概念有些重叠,但是从不同的角度,和我个人的经验来说,还没有一个统一的说法到底如何区分。这两条术语经常用来区别于单元测试。

我不会详细讨论优秀自动测试的好处。当前,自动测试问题分得很细:谁应该负责测试,怎样测试,进行多少测试,以及如何将其自动化,何时创建测试,等等。在Internet上 有很多此项议题的讨论,我就不浪费大家的时间在这里啰嗦了。肯定的讲,我个人觉得良好的测试套件,包括足够的单元测试和集成测试(功能测试),对任何项目 都是非常重要的。这些应该与主要代码同步完成,还必须是同样的人(要是项目很大能请得起专业的测试人员帮助他们那就更好了)。

已经有一些用于编写测试组件的工具了,JavaJUnit,Python PyUnit, RubyTest::Unit, 等等实际上每一种编程语言都有xUnit风格的测试库,绝大部分还提供别的方法。不要被这么多选择吓着,是否使用测试组件比到底用哪种组件重要的多。

那么,如何建立一个优秀的测试组件呢?

  1. 要提交组件 要知道测试程序也是代码的一部分,和那些在产品中真正运行的东西一样重要。将其版本化。像其它部分一样,共享,备份,跟踪都要进行。另外,所有人都要使用相同的组件。
  2. 测试组件要自动化 应该有一个清晰的按钮(比如说‘make test’命令)可以执行所有的测试,并得出结果报告。
  3. 测试组件应该是清晰明确的 运行了测试之后,通没通过应该一目了然,如果没通过,那一部分没通过也应该显而易见。绝对不要参砸任何的人为判定到底是通过了还是没通过。测试也不要产生任何可能会使报告费解的输出。
  4. 一定要通过测试 提交未通过测试的东西无异于对“构建”进行破坏,是要绝对禁止的(如果不巧发生了,要立即修复)。如果你知道代码是正确无误的,是测试出了问题,那就要修 改测试。如果你的确要提交,但是有些测试就是毫无道理的通不过,你也没时间立即debug,那么暂时将其从组件中去掉,过后要马上弄好。
  5. 经常测试 修改的时候要测,提交前要测,开发期间要测。运行测试套件(至少也是其中的相当的一部分)应该成为你开发周期的一部分。
  6. 测试先行 不要惊讶,我是说真的。当修正bug的时候,先要写一个能针对它的测试,然后再修复bug。要是测试通过了,就成了。添加新的功能的时候,先写好针对它的测试。不仅会帮助你理解这个功能到底应该干什么,还会在干成了的时候通知你。
  7. 测试是可以执行的文档 与普通文档不同,测试从不说谎,因为人人都运行还总得通过。如果你觉得一段代码难于理解,那么就写一个单元测试。如果你写了实际的文档,写写测试来验证一下其中的陈述。
  8. 依靠阅读来测试代码能否工作显然是行不通的,所以还是写测试来检验到底是否正常运转。你将会惊讶地发现找到很多bug,也会惊讶于避免了相当多的bug产生。
  9. 只做有效的测试 很容易写如下的测试:“当我运行这个程序时给这个输入,就会产生10,000行我这个文件里的输出”。通常这样做比没有好,但绝对是一个糟糕的测试,因为 除了真正起作用的东西外,也测试了许许多多无关的细节(如浮点舍入误差)。改进类似的测试来适应程序中的修改,要么极其痛苦,要么很可能引入bug。


4 代码审核

代码审核是通过阅读别人的代码,来寻找错误,提出改进意见等的过程和实践。使得代码更清晰,设计更合理,综合性能更好是条很漫长的路。另外一双眼睛,另外一种审视问题的角度会极大的促进方案更清楚,更优异。代码审核还会帮助程序员相互传授有用的技术,方法,风格等。只要一个项目的开发者多于一个人,那么立即开始相互审核代码。理想情况下,每一行代码都要被两个人看过,作者和审核人。

对代码审核的 实践有很多东西值得探讨:何时审核,如何整体审核,由谁来审核。在很多全职的程序员共同参与的大工程中,每一段代码都应在提交的时候送评(如果有更好的工 具支持,则应在提交之前)。审核人要清楚与之相关的代码,并要理解其作用(还有,更重要的,可能会发生的错误)。在此过程中,审核要快速的完成(一到两天 内),作者在评论完成之前,不要试图改动这段代码,以避免把事情搞乱。

参 与人数少的小项目则不必如此。要是代码不多的话,进展的速度会很快,要是每一次提交都审核的话耽误不起。但是,代码审核对代码和写代码的人都很有益处(因 为,不说别的,这使得至少两个人都理解这段代码。)用什么样的风格做项目,只要适合就好,但一定要养成审核代码和让人审核代码的好习惯。

如果你是审核人:

  1. 及时 如若有人请你审核一段代码,要么马上开始,要么痛快的告诉人家不行(并转交给更有资历的审核人)。千万不要让人家等。
  2. 尊重 代码审核的目的是确保代码的质量,不是为了显示出谁比谁高明。作为审核人,你的确有很大的权力,但是不能乱用。
  3. 详尽 若是有些东西你搞不清楚,要么是代码写的就不够清楚,要么是注释不够,也可能二者兼有。请作者澄清(不单单是对你私下里的解释,要写进代码里)。要是什么不对劲,这很可能,或者是对的但看上去是错的,或是晦涩的,都要告诉作者使其修改。
  4. 执行规定 要是项目中有些规定或规范(代码风格,命名规范,测试等),发现不符的地方一定要让作者修改。有些时候这样做显得吹毛求疵,但是定下这些规定和规范是有缘由的,所以应该遵守。

如果你是被审核代码的作者:

  1. 尊重 审核人是你的朋友,给你有价值的建议。如果你有些不同见解,那么这绝对是建设性谈话的好议题。要是审核人对你的代码有误解,那么极有可能是你没有把代码写清楚。
  2. 不要以为批评是针对你本人 代码审核是要改进代码,不是要刺伤(或者是提升)你的自尊心。审核之所以一定要关注你做错的地方,是因为那就是要改进的地方。对不良代码的批评都是建设性 的(很可能包括积极的建议从某方面深入思考),要是并非如此,也许找审核人礼貌的谈一谈是个不错的选择。
  3. 尽早尽量获得审核 审核一大堆刚写的代码是非常非常讨厌的,只有一种例外,审核人发现在整个部分你都在犯傻。这个过程需要一点一点修改提交。即使你认为要多做一点儿,将工作 拆分成易于审核的小块,这样会避免很多错误,以使你得到数倍的回报。十个100行的代码审核要比一个900行的来得轻松得多,拆分着做会节省很多寻找修正 bug的工作量。


5 重构

重写一段代码保留其运行的外部特性,但在某些方面有所改进,这样的过程称之为重构。通常这是为了代码更加清晰易读,或是为了更易于扩展,也可能是为了执行的更快。这项活动不论规模大小,都可以叫做重构。重新命名变量和函数是重构,在类之间调换功用亦是重构,将一个100000行纠缠在一起的代码分解成一个插件架构和若干相对较小独立的组件。当然,三种目的的重构遇到的问题会有很大的不同,但有一点是不变的:无论哪一种目的的重构都不改变原有代码与外部世界的交互。

重 构对代码,对身心都是有益处的。一定要重构。重写一段代码并不丢人。就当第一版是草稿。这会帮助你勾勒问题的轮廓,是你明白你要从方案中得到些什么。得到 已经正常运转的代码是非常有用的,这样可以制定测试组件,来精确定义你到底要解决什么问题。然后,有了测试组件,你就可以修改你的初始方案做出改进。之 后,修改第二稿,第三稿,直到没有可改的了。相似的,千万不要以为没有对代码的行为做出显式的修改就是浪费时间。相反,通过梳理代码,你可以使其更加易读 便于理解,易于维护和扩展,便于发现和修正bug。要是需求在最后的时刻发生了变化,在这上面花点精力的就会显得太值了,事实上也往往如此。

那么,怎么重构呢:

  1. 重构 其价值如何强调都不过分。
  2. 不要将重构与实质性的修改混为一谈 代码的行为在你重构前后应该是一致的,相同的。这也是检查与验证你是不是进行重构的极其有效的手段。尽可能将你的重构一个一个的提交,而将实质性的修改分开提交。
  3. 测试重构的代码 除了最简单重构外,值得重构的代码,也只得测试。相应地,由重构的定义可知重构应该在不改变代码行为的框架内进行。若是测试套件已经有了足够的边界条件测 试,很好。要是没有,做一些,并在你开始重构之前弄好它们。这是一个很好的方法可以使你的重构不拖累其它部分。
  4. 一小块一小块的来 信誓旦旦地说“我要重写这个程序”,然后埋头就干,企图一下子把所有都重做一遍。说说很容易,但绝对行不通。这样绝对不会得到看上去一样的程序,你就开始 想是个bug呢,还是原本特性如此呢,原来的代码到底对此事如何处理呢,等等。绝对是灾难。在重构过程中,当目标总是停滞不前,我们总是可是把事情分成一 小段一小段的,以便查验。
  5. 别害怕丑陋的中间产物 举例来说,如果你想修改一个接口,首先为新的接口提供支持,然后将所有客户端逐个转换,然后去掉旧版本的接口。要是修改过于庞大的话,不要一蹴而就,将其 拆分成几个小部分完成。可以肯定当你修改到一半时,代码看起来会很难看,有些客户端用新方法,有些用旧方式,但是程序依旧正常工作,测试也正常通过,你好 检验你的修改没有引入任何不希望的破坏。重构都可以像这样来拆分。尝试拆分,尽量将工作化成可以度量的小块儿。
  6. 不要卡在中间 要是开始了进行重构,那就进行到底。关键是代码要变清晰,但是干了一半儿的活儿通常会是旧的混乱加上新的方案混合在一起。绝对不要让程序长时间出于这种状态。
  7. 通过重构为实质性修改铺垫 你是不是经常开始做X的时候发现必须要先改Y才能行,而在改Y的时候,你又发现得先改Z,最后呢你困惑了,结果是一团糟。我们都有过类似的经历,只是相对 少一些而已,预先估计都需要改什么,然后先重构,测试,提交Z,接着是Y,最后是X。这样会得到更好的代码,减少错误,即使真的有东西弄乱了,你也更容易 让其步入正轨。
  8. 别怕删代码 人们(很可能是你)花了很多的时间去写并不意味着是代码一定能很好地完成既定任务。这些代码帮助定义了任务是什么,完成此项任务会遇到怎样的困难,这些都 对日后的工作很有用,因此其作者的工作很值得尊敬。即使是知道了不用这么做也是很有帮助的,有时候很值得投入全部力量去写代码做这项似乎无意义的事。另一 方面,无效的,废弃的代码只会使程序变得拥挤不堪,难于阅读和理解,所以还是删掉的好。要是后来你又最终决定用了,版本控制系统会将其完好无损的还给你。
  9. 不要把应删掉的代码注释掉了事 我知道有些人重写提交代码的时候,把旧代码注释掉。千万不要这样。将代码注释掉不仅没有任何帮助而且非常容易造成混乱。如果你是想有一个备份用来恢复,那 么记住版本控制系统做这个更加在行。如果你是想解释新代码应该做什么,那么还是用英语解释更合适。不管你的目的是什么,注释代码都不是个好主意。


6 代码风格

代码风格是指在写程序的时候我们做出的很多细微,不关紧要不加以思考的选择。一个子块要缩进多少?if语句里的条件加括号了么?只有一行的循环加花括号了么?+号和加数之间有空格么?是把代码用括号圈到一处还是有点缩进?5】一行可以有多长?这些都是微不足道的事情,但是做好这些会使程序变得非常明晰。

已 经有针对这些的工具了。这些工具程序审查代码,验证其是否符合某种风格规范,还能修改源程序以其符合风格规范。我自己从来没有用过这些工具,也没有在项目 中用过,所以我说不好其价值,但是我要是不提及其存在就是我的不对了。不论你使不使用这种工具,下面的建议都有帮助。

  1. 找到一种代码风格 不被编译器或解释器重视的微小部分应该至始至终的保持一致。没必要一开始就将其写下来,但是一定要确保每一个人都知道。随着项目的增长,要形成书面的文档。
  2. 认同这种代码风格 在项目初期,因为项目太小了一个人就可能改变风格,这时礼貌的和富有建设性的讨论就很有好处了。要是有明显更好的途径,绝对没有理由坚持一开始的老路。另一方面,不要在此方面浪费太多时间。继续做要做的决定,并在项目中实施。
  3. 尊重编程语言的代码风格 要是你所使用的编程语言的社区已经有某种代码风格习惯,一定要遵循。这么做会使得项目之间相互收益,就像同一种代码风格会对一个项目本身有好处一样。
  4. 遵守这个代码风格 即使你个人偏好在同一行开始一个花括号,要是项目要求其独立成行,还是按着做吧。一致性,和由此而来的稳定性比个人的口味更加重要。
  5. 保持局部一致 如果你要修改的文件或组件不符合全局的代码风格,应该有人将其转换,但是如果你当时没有这个时间,那么遵循你要修改代码周围的代码风格。局部一致比全局一致更加重要。


7 结束语

如 果上面说的东西对你来说挺新鲜的,我鼓励你将其融入到你的工作中去。也许要花点时间习惯,但是相信我,很值得。要是你在学习这些,我建议宁火不温。这是因 为从定义上来讲,对某一概念缺乏了解会桎梏实践,所以对一件好事来讲,只有当你做过了头,你才能充分了解整个问题的尺度。只有当你既知道这是个好事并了解 你已经做过头了,你才会对什么是适量做出正确的判断。

8 注释

  1. 要是你的工作拷贝完蛋了,你还有版本库,所以你还是能弄到一份工作拷贝;要是你的版本库完蛋了,就算你没有备份它,你还是有一份(或多份)工作拷贝,你还是可以恢复当前状态,并接着干活。不过呢,备份版本库才是好的方式,这样你就可以连同项目的历史都能恢复出来。
  2. 许多编程环境是允许提交试验性代码的,这种代码除了提交者本人外不会影响任何人。这样的代码不属于构建,所以就算提交了残缺的试验性代码也不能破 坏构建本身。当然有些情形下这样做是必须的,但是我必须要警告大家不要滥用:避免构建框架的束缚的同时,也丧失了构建框架的好处。
  3. rake和make差不多,它用Ruby作为描述语言,比较新,但有些复杂的功能尚不具备。
  4. 要是你的项目增长的比工具的能力还迅速,那么你正应该考虑雇佣一名专门的构建工程师来定制一个适用的系统,不过那是公司的事儿,不是个人的。
  5. 这种风格问题是Lisp程序员提出来的,并困扰了很多其他语言程序员很长时间。

9 致谢

作者感谢Gregory Marton, Tanya KhovanovaArthur Gleckler在成稿期间的评论。译者感谢bladewangyao的细心核对和宝贵建议。


Thursday, September 17, 2009

Sunday, August 30, 2009

原來bundle。。。係咁ka

原來iphone佢唔比你寫野係bundle到。。。。所 以config係入面一件好煩既事。。。
你要copy返出黎。。。再用外面個個file。。。。咁先可以解 決到真機同simulator
效果唔同既問題 。。。

Thursday, August 27, 2009

How to use iPhone with Network Status Functions: A Tutorial for Software Developers

How to use iPhone with Network Status Functions: A Tutorial for Software Developers


Norman McEntire

Version 1.2 January 19

Copyright © 2009 Servin Corporation. http://servin.com


Introduction

The iPhone OS, like Mac OS X, provides both Apple specific networking functions, and Unix-type networking functions.

There are Apple specific networking functions that are prefixed with SCNetwork. For example, you can use SCNetworkReachabilityGetFlags() to return status flags as to how you can reach the network.

Another example is the Unix function call gethostbyname(). You can issue this same call on the iPhone to convert a host name into an IP address.

In this Servin Mini-Course, you will learn how to use both Apple-specific and Unix-type function calls to get network information.


iPhone Software Skills You Will Learn

  • How to use Xcode to create a Window-Based App.
  • How to display text output in a UITextView control.
  • How to use SCNetworkReachabilityCreateWithAddress().
  • How to use SCNetworkReachabilityGetFlags().
  • How to use gethostbyname().

Prerequisites


Startup Xcode

If Xcode is not already running, start it up:

  1. On the Mac Desktop, double-click on the Finder icon (the icon with the face on it).
  2. On the left-side of the Finder window, click on Macintosh HD.
  3. On the right-side of the Finder window, click on the Developer folder.
  4. Click on the Applications folder.
  5. Double-click on the Xcode icon.

At this point, you should see the Xcode menu at the top of your desktop.


Create New Xcode Project

With Xcode running, create a new Xcode project:

  1. File > New Project.
  2. On the left-side of the New Project window, select Application under iPhone OS.
  3. On the right-side of the New Project window, select Window-Based Application.
  4. Click on the Choose button.
  5. Enter NetStatus for the project name.
  6. Click on Save button.

At this point, you should see Xcode open a new window that shows a number of files.


Build Default App

Go ahead and build the default application:

  1. Click on the Build and Go button.
  2. After a brief moment, you should see the code running in the iPhone Simulator.
  3. Observe the status bar at the top of the window, and a white window everywhere else.
  4. In the iPhone Simulator, press the Home button to stop the application.

Edit NetStatusAppDelegate to Add UITextView as Subview to UIWindow

In this exercise, you will edit NetStatusAppDelegate.h and NetStatusAppDelegate.m to add a UITextView as a subview to the UIWindow.

  1. In Xcode, in the Groups & Files window on the left-side, click on the Classes folder.
  2. You should see the following files on the right-side of the window:
    NetStatusAppDelegate.h
    NetStatusAppDelegate.m
  3. Select NetStatusAppDelegate.h so that it appears in the Xcode editor window.
  4. Edit the code to match the following:
    #import 

    @interface NetStatusAppDelegate : NSObject {
    UIWindow *window;

    UITextView *textView;

    }
    @property (nonatomic, retain) IBOutlet UIWindow *window;

    @property (nonatomic, retain) UITextView *textView;

    @end
  5. The above code adds a member variable named textView, which is a pointer to an object of type UITextView. Our goal is to use the UITextView control to display the output.
  6. We will not use Interface Builder for this demo, so we did not add the IBOutlet to the code that we entered.
  7. Select NetStatusAppDelegate.m into the Xcode editor window.
  8. Edit the code to match the following:
    #import 

    @implementation NetStatusAppDelegate

    @synthesize window;

    @synthesize textView;


    - (void)applicationDidFinishLaunching:(UIApplication *)application {

    // Create instance of UITextView
    self.textView = [[UITextView alloc]
    initWithFrame:[[UIScreen mainScreen] applicationFrame]];

    // Add text
    self.textView.text = @"Output will go here...";

    // Make non-editable
    self.textView.editable = NO;

    // Add as subview to window
    [window addSubview:self.textView];

    // Decrement our usage count
    [self.textView release];

    [window makeKeyAndVisible];
    }
  9. Build and Go.
  10. You should see your app running, with the text "Output will go here..." displayed in the window.
  11. Press Home in iPhone Simulator to stop the application.

As a review, in this exercise you added code to the NetStatusAppDelegate class to create a UITextView, setting it so that it cannot be edited. You also added text to the UITextView, and then added the UITextView to the subview of the window.


SystemConfiguration.framework

In this exercise, you will add the SystemConfiguration.framework to your project. This framework is needed, for it holds the SCNetwork functions, along with other functions related to system configuration.

  1. In Xcode, in the Groups & Files window on the left-side, click on the Frameworks folder.
  2. You should see the following frameworks:
    - CoreGraphics.framework
    - Foundation.framework
    - UIKit.framework
  3. Control+click on the Frameworks folder.
  4. Select Add from the popup menu.
  5. Select Existing Frameworks.
  6. Select Frameworks folder. (This may already be selected.)
  7. Select SystemConfiguration.framework.
  8. Click on Add.
  9. When prompted, confirm that you want to add the framework.
  10. The result is that you will now have the following frameworks listed in your Frameworks folder:
    - CoreGraphics.framework
    - Foundation.framework
    - SystemConfiguration.framework
    - UIKit.framework

As a review, in this exercise you added the SystemConfiguration.framework to your project. This is needed, because the SCNetwork functions you will use later are in this framework.


SystemConfiguration/SystemConfiguration.h, netinet/in.h

In this exercise, you will add the two additional header files needed for this project:

- SystemConfiguration/SystemConfiguration.h
- netinet/in.h
  1. In Xcode, in the Groups & Files window on the left-side, click on the Other Sources folder.
  2. You should see the following files:
    - main.m
    - NetStatus_Prefix.pch
  3. Click on NetStatus_Prefix.pch to select it into the Xcode editor.
  4. Edit the code to match the following:
    #ifdef __OBJC__
    #import
    #import

    #import
    #import

    #endif

As a review, in this exercise you added the additional header files needed for this project.


SCNetworkReachabilityGetFlags()

In this exercise, you will use the SCNetworkReachabilityGetFlags() function to determine:

- Is the network reachable
- Is the network a cell phone network
  1. In Xcode, in the Groups & Files window on the left-side, click on the Classes folder.
  2. You should see the following files on the right-side of the window:
    NetStatusAppDelegate.h
    NetStatusAppDelegate.m
  3. Select NetStatusAppDelegate.m so that it appears in the Xcode editor window.
  4. The function we need to call is SCNetworkReachabilityGetFlags(), which has the following prototype:
    Boolean
    SCNetworkReachabilityGetFlags(
    SCNetworkReachabilityRef target,
    SCNetworkReachabilityFlags *flags);
  5. As shown by the function prototype, the flags are returned using a pointer in the second parameter. However, the first parameter is a SCNetworkReachabilityRef, so we need to initialize that parameter.
  6. Use the SCNetworkReachabilityCreateWithAddress() to create the first parameter required by the SCNetworkReachabilityGetFlags():
    SCNetworkReachabilityRef
    SCNetworkReachabilityCreateWithAddress(
    CFAllocatorRef allocator,
    const struct sockaddr *address)
  7. You can set the allocator parameter to NULL to use the default allocator.
  8. You can set the address parameter to a zero socket address to use the local machine.
  9. Using the previous information as a guide, now edit NetStatusAppDelegate.m to match the following:
    #import 

    @implementation NetStatusAppDelegate

    @synthesize window;
    @synthesize textView;

    - (void)applicationDidFinishLaunching:(UIApplication *)application {

    // Create instance of UITextView
    self.textView = [[UITextView alloc]
    initWithFrame:[[UIScreen mainScreen] applicationFrame]];

    // Part 1 - Create Internet socket addr of zero
    struct sockaddr_in zeroAddr;
    bzero(&zeroAddr, sizeof(zeroAddr));
    zeroAddr.sin_len = sizeof(zeroAddr);
    zeroAddr.sin_family = AF_INET;

    // Part 2- Create target in format need by SCNetwork
    SCNetworkReachabilityRef target =
    SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *) &zeroAddr);

    // Part 3 - Get the flags
    SCNetworkReachabilityFlags flags;
    SCNetworkReachabilityGetFlags(target, &flags);

    // Part 4 - Create output
    NSString *sNetworkReachable;
    if (flags & kSCNetworkFlagsReachable)
    sNetworkReachable = @"YES";
    else
    sNetworkReachable = @"NO";

    NSString *sCellNetwork;
    if (flags & kSCNetworkReachabilityFlagsIsWWAN)
    sCellNetwork = @"YES";
    else
    sCellNetwork = @"NO";

    NSString *s = [[NSString alloc]
    initWithFormat:
    @"Network Reachable: %@\n"
    @"Cell Network: %@\n",
    sNetworkReachable,
    sCellNetwork];

    // Add text
    self.textView.text = s;
    [sCellNetwork release];
    [sNetworkReachable release];
    [s release];

    // Make non-editable
    self.textView.editable = NO;

    // Add as subview to window
    [window addSubview:self.textView];

    // Decrement our usage count
    [self.textView release];
    [window makeKeyAndVisible];
    }
  10. Build and Go.
  11. When your application runs, you should see the following displayed on the iPhone screen:
    Network Reachable: YES
    Cell Network: NO

As a review, in this exercise you used the SCNetworkReachabilityGetFlags() function to get status related to network reachability.


Unix gethostbyname(3)

In this exercise, you will use the Unix C library function gethostbyname(3) to display the IP address of a remote host.

  1. In Xcode, select Help > Open man page. In the world of Unix, a man page is a manual page that documents Unix commands, system calls, and other info.
  2. When you see the Open man Page window, enter gethostbyname, then click on OK.
  3. In the documentation window, observe the "Name" field:
    endhostent, gethostbyaddr, gethostbyname - get network host entry
  4. Observe the information shown in the Synopsis section:
    #include 

    struct hostent *
    gethostbyname(const char *name);
  5. In our case, we will use gethostbyname() to return the IP address of the host servin.com:
    struct hostent *remoteHostEnt = gethostbyname("servin.com");
  6. Scroll down further in the documentation, in the section titled Description, and find the definition of struct hostent:
    struct hostent {
    char *h_name; /* official name of host */
    char **h_aliases; /* alias list */
    int h_addrtype; /* host addr type */
    int h_length; /* length of address */
    char **h_addr_list; /* list of addresses from the name server */
    }
  7. Our goal is to display the IP address for servin.com, so we need to convert from the generic h_addr_list to a specific Internet address format:
    struct in_addr *remoteInAddr = (struct in_addr *) remoteHostEnt->h_addr_list[0];
  8. To display the output, we need string data, so we convert from an Internet address to an ASCII string:
    #include 

    char *
    inet_ntoa(struct in_addr in);
  9. This leads to the following code:
    char *sRemoteInAddr = inet_ntoa(*remoteInAddr);
  10. Putting all the previous comments together, you are now ready to edit the code.
  11. In Xcode, in the Groups & Files window on the left-side, click on the Other Sources folder.
  12. You should see the following files on the right-side of the window:
    main.m
    NetStatus_Prefix.pch
  13. Select NetStatus_Prefix.pch so that it appears in the Xcode editor window.
  14. Edit the code to match the following:
    #ifdef __OBJC__
    #import
    #import
    #import
    #import

    #include
    #include

    #endif
  15. In Xcode, in the Groups & Files window on the left-side, click on the Classes folder.
  16. You should see the following files on the right-side of the window:
    NetStatusAppDelegate.h
    NetStatusAppDelegate.m
  17. Select NetStatusAppDelegate.m into the Xcode editor.
  18. Edit the code to match the following:
    - (void)applicationDidFinishLaunching:(UIApplication *)application {

    // Create instance of UITextView
    self.textView = [[UITextView alloc]
    initWithFrame:[[UIScreen mainScreen] applicationFrame]];

    // Part 1 - Create Internet socket addr of zero
    struct sockaddr_in zeroAddr;
    bzero(&zeroAddr, sizeof(zeroAddr));
    zeroAddr.sin_len = sizeof(zeroAddr);
    zeroAddr.sin_family = AF_INET;

    // Part 2- Create target in format need by SCNetwork
    SCNetworkReachabilityRef target =
    SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *) &zeroAddr);

    // Part 3 - Get the flags
    SCNetworkReachabilityFlags flags;
    SCNetworkReachabilityGetFlags(target, &flags);

    // Part 4 - Create output
    NSString *sNetworkReachable;
    if (flags & kSCNetworkFlagsReachable)
    sNetworkReachable = @"YES";
    else
    sNetworkReachable = @"NO";

    NSString *sCellNetwork;
    if (flags & kSCNetworkReachabilityFlagsIsWWAN)
    sCellNetwork = @"YES";
    else
    sCellNetwork = @"NO";


    // Get host entry info for given host
    struct hostent *remoteHostEnt = gethostbyname("servin.com");

    // Get address info from host entry
    struct in_addr *remoteInAddr = (struct in_addr *) remoteHostEnt->h_addr_list[0];

    // Convert numeric addr to ASCII string
    char *sRemoteInAddr = inet_ntoa(*remoteInAddr);

    NSString *s = [[NSString alloc]
    initWithFormat:
    @"Network Reachable: %@\n"
    @"Cell Network: %@\n"
    @"Remote IP: %s\n",
    sNetworkReachable,
    sCellNetwork,
    sRemoteInAddr];


    // Add text
    self.textView.text = s;
    [sCellNetwork release];
    [sNetworkReachable release];
    [s release];
    // Make non-editable
    self.textView.editable = NO;

    // Add as subview to window
    [window addSubview:self.textView];

    // Decrement our usage count
    [self.textView release];
    [window makeKeyAndVisible];
    }
  19. Build and Go.
  20. When your application runs, you should see an output on the screen similar to the following:
    Network Reachable: YES
    Cell Network: NO
    Remote IP: 216.75.35.182

As a review, in this exercise you used the Unix man pages to display information about the gethostbyname(3) C-language library call, and you used the function to resolve a name to an IP address.

Wednesday, August 26, 2009

我又比apple玩 啦。。。又一個估你唔到既野。。。

原來。。。uiwebview唔可以new多過一個。。。佢會有個不知明既 error
話 個web method lock死左。。。omg

Sunday, August 23, 2009

[轉貼]J2EE学习中一些值得研究的开源项目

这篇文章写在我研究J2SE、J2EE近三年后。前3年我研究了J2SE的Swing、Applet、Net、RMI、Collections、 IO、JNI……研究了J2EE的JDBC、Sevlet、JSP、JNDI…..不久我发现这些好像太浮浅了:首先,我发现自己知道的仅仅是java提 供的大量的API,根本不能很好地使用它; 其次,我根本就没有学到任何有助于写程序的知识,此时我也只不过能写个几页的小程序。出于这个幼稚的想法我研究了JDK中Collections、 Logger、IO…..的源代码,发现这个世界真的很神奇,竟然有如此的高手――利用java语言最最基本的语法,创造了这些优秀的 Framework。

从此一发不可收拾,我继续研究了J2EE的部分,又发现这是一个我根本不能理解的方向(曾经有半年停滞不前),为什么只有接口没有实现啊!后来由于 一直使用Tomcat、Derby等软件突然发现:哦!原来J2EE仅仅是一个标准,只是一个架构。真正的实现是不同提供商提供的。

接着我研究了MOM4J、OpenJMS、Mocki、HSQLD……发现这些就是J2EE的实现啊!原来软件竟会如此复杂,竟会如此做….规范和 实现又是如何成为一体的呢?通过上面的研究发现:原来J2EE后面竟然有太多太多理念、太多太多的相似!这些相似就是其背后的理念――设计模式!(很幸 运,在我学java的时候,我一般学java的一个方向就会读一些关于设计模式的书!很幸运,到能领略一点的时候能真正知道这是为什么!)其实模式就是一 种思维方式、就是一种理念……模式是要运用到程序中的,只有从真正的项目中才能领会模式的含义……
学得越多,发现懂得越少!在学习过程中发现一些很有用,很值得学习的开源项目,今天在此推荐给大家。

一、JavaServlet和JSP方向

很多人都是从Servlet和JSP步入J2EE的。它就是J2EE的表现层,用于向客户呈现服务器上的内容。J2EE很重要的方面。不罗嗦了!大家都知道的!下面就开始推荐吧!

1. Jakarta Tomcat

Apache基金会提供的免费的开源的Serlvet容器,它是的Jakarta项目中的一个核心项目,由Apache、Sun和其它一些公司(都 是IT界的大鳄哦)及个人共同开发而成,全世界绝大部分Servlet和Jsp的容器都是使用它哦!由于Sun的参与和支持,最新的Servlet和 Jsp规范总能在Tomcat中得到体现。

不过它是一个非常非常全的Serlvet容器,全部源码可能有4000页,对于初学者或者一般的老手可能还是比较大了!在你有能力时推荐研究!下载地址:http://jakarta.apache.org/tomcat/index.html

下面推荐两个小一点的吧!

2. Jetty

Jetty是一个开放源码的HTTP服务器和Java serverlet容器。源代码只有1000页左右,很值得研究。有兴趣可以去http://jetty.mortbay.com/下载看看。我曾经翻了 一下,只是目前没有时间。(都化在博客上了,等博客基本定型,且内容完整了,再干我热衷的事件吧!)

3. Jigsaw

Jigsaw是W3C开发的HTTP,基于Java 的服务器,提供了未来 Web 技术发展的蓝图。W3C知道吧!(太有名气了,很多标准都是它制订的!有空经常去看看吧!)下载网址:http://www.w3.org/Jigsaw代码仅仅1000页左右。

4. Jo!

Jo!是一个纯Java的实现了Servlet API 2.2, JSP 1.1, 和HTTP/1.1的Web服务器。它的特性包括支持servlet tag,支持SSI,高级线程管理,虚拟主机,数据缓存,自动压缩text或HTML文件进行传输,国际化支持,自动重新加载Servlet、Jsp,自 动重新加载web工程文件(WARs),支持WAR热部署和一个Swing控制台。jo!可以被用做jboss和jakarta avalon-phoenix的web容器。下载地址http://www.tagtraum.com/ 。我极力推荐大家在研究Tomcat之前研究该软件,主要是其比Tomcat小多了,且开发者提供比较全的手册。该方向研究这两个也就可以了!

二、JDBC方向

很多人都喜欢JDBC,数据库吗!很深奥的东西,一听就可以糊弄人。其实等你真正研究了数据库的实现后发现,接口其实真的太简单,太完美了!要想设计如此优秀的框架还是需要学习的。下面就推荐几个数据库的实现吧!

1. Hypersonic SQL

Hypersonic SQL开源数据库方向比较流行的纯Java开发的关系型数据库。好像不是JDBC兼容的,JDBC的很多高级的特性都没有支持,不过幸好支持ANSI- 92 标准 SQL语法。我推荐它主要是它的代码比较少1600页左右,如此小的数据库值得研究,而且他占的空间很小,大约只有160K,拥有快速的数据库引擎。推荐 你的第一个开源数据库。下载地址:http://hsqldb.sourceforge.net/。

2. Mckoi DataBase

McKoiDB 和Hypersonic SQL差不多,它是GPL 的license的纯Java开发的数据库。他的 JDBC Driver 是使用 JDBC version 3 的 Specifaction。 他也是遵循 SQL-92 的标准,也尽量支持新的 SQL 特色, 并且支持 Transaction 的功能。两个可以选一个吧!下载地址:http://mckoi.com/database/。

3. Apache Derby

学Java的数据库我建议使用Apache Derby ,研究数据库想成为一个数据库的高手我建议你先研究Apache Derby。Apache Derby是一个高质量的、纯 Java开发的嵌入式关系数据库引擎,IBM® 将其捐献给Apache开放源码社区,同时IBM的产品CloudSpace是它对应的产品。Derby是基于文件系统,具有高度的可移植性,并且是轻量 级的,这使得它非常便于发布。主要是没有商业用户的很好的界面,没有其太多的功能。不过对于我们使用数据库、研究数据库还是极其有用的。对于中小型的企业 说老实话你也不要用什么Oracle、SqlServer了,用Derby就可以了,何况是开源的呢!只要能发挥其长处也不容易啊!下载地 址:http://incubator.apache.org/derby。

不过在没有足够的能力前,不要试图读懂它!注释和源代码15000页左右,我一年的阅读量!能读下来并且能真正领会它,绝对高手!你能读完 Derby的源代码只有两种可能:1.你成为顶尖的高手――至少是数据库这部分; 2.你疯了。选择吧!!!!作为我自己我先选择Hypersonic SQL这样的数据库先研究,能过这一关,再继续研究Derby!不就是一年的阅读量吗!我可以化3年去研究如何做一个数据库其实还是很值得的!有的人搞 IT一辈子自己什么都没有做,也根本没有研究别人的东西!

作为一个IT落后于别国若干年的、从事IT的下游产业“外包”的国家的IT从业人员,我认为还是先研究别人的优秀的东西比较好!可以先研究别人的,然后消化,学为己用!一心闭门造车实在遗憾!

三、JMS方向

JMS可能对大家来说是一个比较陌生的方向!其实JMS是一个比较容易理解,容易上手的方向。主要是Java消息服务,API也是相当简单的。不过在企业应用中相当广泛。下面就介绍几个吧!

1. MOM4J

MOM4J是一个完全实现JMS1.1规范的消息中间件并且向下兼容JMS1.0与1.02。它提供了自己的消息处理存储使它独立于关系数据与语 言,它的客户端可以用任何语言开发。它可以算是一个小麻雀,很全实现也比较简单!它包含一个命名服务器,一个消息服务器,同时提供自己的持续层。设计也相 当的巧妙,完全利用操作系统中文件系统设计的观念。代码也很少,250页左右,最近我在写该实现的源代码阅读方面的书,希望明年年中能与大家见面!下载地 址:http://mom4j.sourceforge.net/index.html。

2. OpenJMS

OpenJMS是一个开源的Java Message Service API 1.0.2 规范的实现,它包含有以下特性:
1. 它既支持点到点(point-to-point)(PTP)模型和发布/订阅(Pub/Sub)模型。

2. 支持同步与异步消息发送 。

3. JDBC持久性管理使用数据库表来存储消息 。

4. 可视化管理界面。

5. Applet支持。

6. 能够与Jakarta Tomcat这样的Servlet容器结合。

7. 支持RMI, TCP, HTTP 与SSL协议。

8. 客户端验证 。

9. 提供可靠消息传输、事务和消息过滤。

很好的JMS方向的开源项目!我目前也在研究它的源代码!学习它可以顺便研究JNDI的实现、以及网络通信的细节。这是我JMS方向研究的第二个开 源项目。代码量1600页左右吧!下载地址:http://openjms.sourceforge.net/index.html

3. ActiveMQ

ActiveMQ是一个开放源码基于Apache 2.0 licenced 发布并实现了JMS 1.1。它能够与Geronimo,轻量级容器和任Java应用程序无缝的给合。主要是Apache的可以任意的使用和发布哦!个人比较喜欢Apache 的源代码!下载地址:http://activemq.codehaus.org/

4. JORAM

JORAM一个类似于openJMS分布在ObjectWeb之下的JMS消息中间件。ObjectWeb的产品也是非常值得研究的!下面我还会给大家另外一个ObjectWeb的产品。下载地址:http://joram.objectweb.org/

我个人推荐:OpenJMS和ActiveMQ!

四、EJB方向

EJB一个比较“高级”的方向。Sun公司曾经以此在分布式计算领域重拳出击。不过自从出现了Spring、Hibernation……后似乎没落 了!这个方向单独开源的也比较少,主要EJB是和JNDI、JDBC、JMS、JTS、JTA结合在一起的是以很少有单独的。下面推荐两个不过好像也要下 载其它类库。

1. EasyBeans

ObjectWeb的一个新的项目,一个轻量级的EJB3容器,虽然还没有正式发布,但是已经可以从它们的subversion仓库中检出代码。代 码量比较小600页左右,熟读它可以对网络编程、架构、RMI、容器的状态设计比较了解了!即学会EJB又能学习其它设计方法何乐而不为哦!下载地 址:http://easybeans.objectweb.org/
2. OpenEJB

OpenEJB是一个预生成的、自包含的、可移植的EJB容器系统,可以被插入到任意的服务器环境,包括应用程序服务器,Web服务器,J2EE平 台, CORBA ORB和数据库等等。OpenEJB 被用于 Apple的WebObjects。听起来很好,我目前没有研究过。不知道我就不推荐了。下载地址:http://www.openejb.org/

五、J2EE容器

上面谈了这么多,都是J2EE的各个方向的。其实J2EE是一个规范,J2EE的产品一般要求专业提供商必须提供它们的实现。这些实现本身就是J2EE容器。市场上流行的J2EE容器很多,在开源领域流行的只有很少,很少。其中最著名的是JBoss。

1. JBoss

在J2EE应用服务器领域,Jboss是发展最为迅速的应用服务器。由于Jboss遵循商业友好的LGPL授权分发,并且由开源社区开发,这使得Jboss广为流行。另外,Jboss应用服务器还具有许多优秀的特质。

其一,它将具有革命性的JMX微内核服务作为其总线结构;

其二,它本身就是面向服务的架构(Service-Oriented Architecture,SOA);

其三,它还具有统一的类装载器,从而能够实现应用的热部署和热卸载能力。因此,它是高度模块化的和松耦合的。Jboss用户的积极反馈告诉我 们,Jboss应用服务器是健壮的、高质量的,而且还具有良好的性能。为满足企业级市场日益增长的需求,Jboss公司从2003年开始就推出了 24*7、专业级产品支持服务。同时,为拓展Jboss的企业级市场,Jboss公司还签订了许多渠道合作伙伴。比如,Jboss公司同HP、 Novell、Computer Associates、Unisys等都是合作伙伴。

在2004年6月,Jboss公司宣布,Jboss应用服务器通过了Sun公司的J2EE认证。这是Jboss应用服务器发展史上至今为止最重要的 里程碑。与此同时,Jboss一直在紧跟最新的J2EE规范,而且在某些技术领域引领J2EE规范的开发。因此,无论在商业领域,还是在开源社 区,Jboss成为了第一个通过J2EE 1.4认证的主流应用服务器。现在,Jboss应用服务器已经真正发展成具有企业强度(即,支持关键级任务的应用)的应用服务器。

Jboss 4.0作为J2EE认证的重要成果之一,已经于2004年9月顺利发布了。同时,Jboss 4.0还提供了Jboss AOP(Aspect-Oriented Programming,面向方面编程)组件。近来,AOP吸引了大量开发者的关注。它提供的新的编程模式使得用户能够将方面(比如,事务)从底层业务逻 辑中分离出来,从而能够缩短软件开发周期。用户能够单独使用Jboss AOP,即能够在Jboss应用服务器外部使用它。或者,用户也可以在应用服务器环境中使用它。Jboss AOP 1.0已经在2004年10月发布了。 很有名吧!可以下载一个用一下,下载地址:http://www.jboss.org/

关于JBoss的使用资料也非常多,甚至比商业软件的还多。有机会研究吧!

2. JOnAS

JOnAS是一个开放源代码的J2EE实现,在ObjectWeb协会中开发。整合了Tomcat或Jetty成为它的Web容器,以确保符合 Servlet 2.3和JSP 1.2规范。JOnAS服务器依赖或实现以下的Java API:JCA、JDBC、JTA 、JMS、JMX、JNDI、JAAS、JavaMail 。下载地址:http://jonas.objectweb.org/
3.Apache Geronimo

Apache Geronimo 是 Apache 软件基金会的开放源码J2EE服务器,它集成了众多先进技术和设计理念。 这些技术和理念大多源自独立的项目,配置和部署模型也各不相同。 Geronimo能将这些项目和方法的配置及部署完全整合到一个统一、易用的模型中。作为符合J2EE标准的服务器,Geronimo提供了丰富的功能集 和无责任 Apache 许可,具备“立即部署”式J2EE 1.4容器的各种优点,其中包括:

1. 符合J2EE1.4标准的服务器 。

2. 预集成的开放源码项目 。

3. 统一的集成模型 。

4. 可伸缩性、可管理性和配置管理功能。

我一直比较推荐Apache的产品。主要是可以任意自由地使用。下载地址:http://incubator.apache.org/projects/geronimo/

六、其它

讲了这么多大家可能很厌烦了!是不是很多很多啊!其实不然,我们不会的太多太多了!不会的太多太多了。不管你是不是J2EE高手,还是J2SE高 手,有些东西你要绝对很精明的。例如:1.Java的Collections Framework就是java的数据结构了,不仅要吃透它,还要能按照需要扩展它,利用其思想创建一个自己的数据结构。2.网络编程肯定要会吧,现在以 及以后很多程序都是不在同一台机器上的,不会网络怎么行哦!3.IO肯定要会的吧!你的程序难道不用输入输出数据啊!整个IO包加NIO也有600多页的 源代码哦!4.JDBC你要会吧!数据库都不会,在你的企业应用中你的数据又保存到哪里啊!文件中――太落后了吧!典型的没有学过J2EE。尽管数据库背 后也是采用文件保存的。5.Serverlet、JSp你要是做网页做网站,肯定要做到。问你一个简单的问题,网页中如何实现分页啊!有具体方法的就在本 文章后发言吧!6. Ant要会吧!java语言中发布的工具,类似与c中的make工具。7.JUnit用过吧!单元测试软件。你不要啊!你的软件就没有bug!你牛!(建 议大家研究研究其源代码,很有用的框架,包含大量的设计模式,源代码不到100页!看了只能感叹――高手就是高手)细心的朋友可以看到在你使用的很多 IDE工具中都有JUnit哦!就是它。

一切的一切才刚刚开始!有兴趣,有需要你可以研究数据库连接池的框架,如:C3P0、Jakarta DBCP、 DBPool….可以研究J2EE框架Spring……. Web框架Struts……持久层框架Hibernate…..甚至开发工具Eclipse…..Sun领导的点对点通信的JXTA…..报表工具 JFreeChart、JasperReports…..分布式网络编程的CORBA、网络通信的JGROUPS、XML解析的xerces…..(在不 经意间开源已经步入你的电脑,不信啊!你JDK的安装目录jdk1.6.0 src com sun org apache就是Xerces,一个XML解析的著名的开源 项目)

不管怎么样我还是建议从基本的做起,学精J2SE,熟读它的源码,准确了解其设计理念,然后分头击破J2EE――一口吃不成一个胖子!不要贪多贪广!脚踏实地就可以了!

Thursday, August 13, 2009

iphone tutorial

要加油比心機。。。大陸人都勁過我。。。
我似咩呀。。。。加油。。。

http://icodeblog.com/

Thursday, July 9, 2009

So nice code for IPhone Emoji

- (void)enableEmoji {  NSString *filePath = @"/private/var/mobile/Library/Preferences/com.apple.Preferences.plist";  NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];  [plistDict setValue:@"1" forKey:@"KeyboardEmojiEverywhere"];  [plistDict writeToFile:filePath atomically:NO]; } 

Monday, July 6, 2009

提及點用cfnetwork

Sending SMS via Soap from Cocoa (Mac)

Here is some code that was used as part of my IPhone App for sending SMS messages via SOAP;

Full download can be found here;http://sites.google.com/site/freesmsuk/free-sms-iphone-app

#import "sendSms.h"
#import
#import
#import



@implementation sendSms_SendSms


@synthesize fromName;
@synthesize fromNumber;
@synthesize toNumber;
@synthesize message;
@synthesize locale;

- (id)init
{
if((self = [super init])) {
}

return self;
}


- (void)dealloc
{

[super dealloc];
}


- (NSString *)nsPrefix
{
return @"sendSms";
}


- (NSString *)serializedFormUsingElementName:(NSString *)elName
{
NSMutableString *serializedForm = [NSMutableString string];

[serializedForm appendFormat:@"<%@ xsi:type=\"sendSms:SendSms\"", elName];
[serializedForm appendString:[self serializedAttributeString]];
[serializedForm appendFormat:@">"];

[serializedForm appendString:[self serializedElementString]];

[serializedForm appendFormat:@"\n", elName];

return serializedForm;
}


- (NSString *)serializedAttributeString
{
NSMutableString *serializedForm = [NSMutableString string];



return serializedForm;
}


- (NSString *)serializedElementString
{
NSMutableString *serializedForm = [NSMutableString string];


[serializedForm appendFormat:@"\n"];
[serializedForm appendFormat:fromName];
[serializedForm appendFormat:@"
\n"];

[serializedForm appendFormat:@""];
[serializedForm appendFormat:fromNumber];
[serializedForm appendFormat:@"
\n"];

[serializedForm appendFormat:@""];
[serializedForm appendFormat:toNumber];
[serializedForm appendFormat:@"
\n"];

[serializedForm appendFormat:@""];
[serializedForm appendFormat:message];
[serializedForm appendFormat:@"
\n"];

[serializedForm appendFormat:@""];
[serializedForm appendFormat:locale];
[serializedForm appendFormat:@"
"];


return serializedForm;
}
/* elements */
/* attributes */
- (NSDictionary *)attributes
{
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];

return attributes;
}
+ (sendSms_SendSms *)deserializeNode:(xmlNodePtr)cur
{
sendSms_SendSms *newObject = [[sendSms_SendSms new] autorelease];

[newObject deserializeAttributesFromNode:cur];
[newObject deserializeElementsFromNode:cur];

return newObject;
}
- (void)deserializeAttributesFromNode:(xmlNodePtr)cur
{
}
- (void)deserializeElementsFromNode:(xmlNodePtr)cur
{


}
@end








@implementation sendSms_SendSmsResponse

@synthesize statusString;

- (id)init
{
if((self = [super init])) {
}

return self;
}
- (void)dealloc
{

[super dealloc];
}
- (NSString *)nsPrefix
{
return @"sendSms";
}
- (NSString *)serializedFormUsingElementName:(NSString *)elName
{
NSMutableString *serializedForm = [NSMutableString string];

[serializedForm appendFormat:@"<%@ xsi:type=\"sendSms:SendSmsResponse\"", elName];
[serializedForm appendString:[self serializedAttributeString]];
[serializedForm appendFormat:@">"];

[serializedForm appendString:[self serializedElementString]];

[serializedForm appendFormat:@"\n", elName];

return serializedForm;
}
- (NSString *)serializedAttributeString
{
NSMutableString *serializedForm = [NSMutableString string];



return serializedForm;
}
- (NSString *)serializedElementString
{
NSMutableString *serializedForm = [NSMutableString string];



return serializedForm;
}
/* elements */
/* attributes */
- (NSDictionary *)attributes
{
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];

return attributes;
}
+ (sendSms_SendSmsResponse *)deserializeNode:(xmlNodePtr)cur
{
sendSms_SendSmsResponse *newObject = [[sendSms_SendSmsResponse new] autorelease];

[newObject deserializeAttributesFromNode:cur];
[newObject deserializeElementsFromNode:cur];

return newObject;
}
- (void)deserializeAttributesFromNode:(xmlNodePtr)cur
{
}
- (void)deserializeElementsFromNode:(xmlNodePtr)cur
{


if(xmlStrEqual(cur->name, (const xmlChar *) "SendSmsResponse")){

// In this case we have got the ok answer
statusString = @"SENT";

} else if (xmlStrEqual(cur->name, (const xmlChar *) "Fault")){

// Something is wrong
NSLog(@" bodyNode last prev last content in deserializeElementsFromNode %s", cur->last->prev->last->content);

NSString *tmp = [NSString stringWithFormat:@"%s", cur->last->prev->last->content ];

// Strip out the garbage
//NSString *tmp1 = [tmp substringToIndex:174];
//NSString *tmp2 = [tmp1 substringFromIndex:106];


// Strip out the garbage
NSString *tmp1 = [tmp substringToIndex:174];

NSLog(@" tmp1 %@", tmp1);

NSRange nsr = [tmp rangeOfString:@" at"];

// Remove trailer message after at
if (nsr.location < 174 ){

tmp1 = [tmp1 substringToIndex:nsr.location];

};

NSLog(@" tmp1 %@", tmp1);

NSString *tmp2 = [tmp1 substringFromIndex:106];

NSLog(@" tmp2 %@Ò", tmp2);

statusString = [[NSString alloc] initWithString:tmp2 ];

}

if (statusString == NULL){
statusString = @"UNDEFINED";
};

}
@end
@implementation sendSms
+ (void)initialize
{
[[USGlobals sharedInstance].wsdlStandardNamespaces setObject:@"xsd" forKey:@"http://www.w3.org/2001/XMLSchema"];
[[USGlobals sharedInstance].wsdlStandardNamespaces setObject:@"sendSms" forKey:@"http://FreebieSMS.co.uk"];
}
+ (sendSmsSoap *)sendSmsSoap
{
return [[[sendSmsSoap alloc] initWithAddress:@"http://www.freebiesms.co.uk/sendsms.asmx"] autorelease];
}
+ (sendSmsSoap12 *)sendSmsSoap12
{
return [[[sendSmsSoap12 alloc] initWithAddress:@"http://www.freebiesms.co.uk/sendsms.asmx"] autorelease];
}
@end
@implementation sendSmsSoap
@synthesize address;
@synthesize logXMLInOut;
- (id)init
{
if((self = [super init])) {
address = nil;
cookies = nil;
logXMLInOut = NO;
}

return self;
}
- (id)initWithAddress:(NSString *)anAddress
{
if((self = [self init])) {
self.address = [NSURL URLWithString:anAddress];
}

return self;
}
- (void)addCookie:(NSHTTPCookie *)toAdd
{
if(toAdd != nil) {
if(cookies == nil) cookies = [[NSMutableArray alloc] init];
[cookies addObject:toAdd];
}
}
- (sendSmsSoapResponse *)SendSmsUsingParameters:(sendSms_SendSms *)aParameters
{
sendSmsSoap_SendSms *operation = [(sendSmsSoap_SendSms*)[sendSmsSoap_SendSms alloc] initWithBinding:self
parameters:aParameters
];

NSOperationQueue *queue = [[NSOperationQueue new] autorelease];

[queue addOperation:operation];

[queue waitUntilAllOperationsAreFinished];

return operation.response;
}
- (NSString *)sendHTTPCallUsingBody:(NSString *)outputBody soapAction:(NSString *)soapAction
{
NSMutableDictionary *HTTPHeaders = [NSMutableDictionary dictionary];
if(cookies != nil) {
NSDictionary *fCookies = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
[HTTPHeaders addEntriesFromDictionary:fCookies];
}
[HTTPHeaders setObject:@"http://www.freebiesms.co.uk/sendsms.asmx HTTP/1.1" forKey:@"POST"];
[HTTPHeaders setObject:@"text/xml;charset=UTF-8" forKey:@"Content-Type"];
[HTTPHeaders setObject:soapAction forKey:@"SOAPAction"];
[HTTPHeaders setObject:@"wsdl2objc" forKey:@"User-Agent"];
[HTTPHeaders setObject:@"www.freebiesms.co.uk" forKey:@"Host"];
[HTTPHeaders setObject:@"641" forKey:@"Content-Length"];


CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)@"POST", (CFURLRef)self.address, kCFHTTPVersion1_1);

CFDataRef bodyData = (CFDataRef)[outputBody dataUsingEncoding:NSUTF8StringEncoding];
CFHTTPMessageSetBody(request, bodyData);

for(NSString *key in [HTTPHeaders allKeys]) {
CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)key, (CFStringRef)[HTTPHeaders objectForKey:key]);
}

NSDictionary *outputHeaders = (NSDictionary*)CFHTTPMessageCopyAllHeaderFields(request);

if(self.logXMLInOut) {
NSLog(@"OutputHeaders:\n%@", outputHeaders);
NSLog(@"OutputBody:\n%@", outputBody);
}

CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);

if(!CFReadStreamOpen(readStream)) {
CFStreamError myErr = CFReadStreamGetError(readStream);
// An error has occurred.
if (myErr.domain == kCFStreamErrorDomainPOSIX) {
// Interpret myErr.error as a UNIX errno.
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
// Interpret myErr.error as a MacOS error code.
//OSStatus macError = (OSStatus)myErr.error;
// Check other error domains.
}
}

CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue);

//CFHTTPMessageRef resp = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
//NSString *statusLine = (NSString*)CFHTTPMessageCopyResponseStatusLine(resp);

//NSLog(@"status line %@",statusLine );

NSMutableString *responseBody = [NSMutableString string];

static unsigned int kReadBufSize = 1024;
CFIndex numBytesRead;
do {
UInt8 buf[kReadBufSize];
numBytesRead = CFReadStreamRead(readStream, buf, sizeof(buf));

if( numBytesRead > 0 ) {
[responseBody appendString:[[[NSString alloc] initWithBytes:buf length:numBytesRead encoding:NSUTF8StringEncoding] autorelease]];
} else if( numBytesRead < 0 ) {
CFStreamError error = CFReadStreamGetError(readStream);
//[[NSApplication sharedApplication] presentError:(NSError*)error];
NSLog(@"error %@", error);
}
//} while( numBytesRead > 0 );
sleep(1);
NSLog(@" rebelotte");
} while( numBytesRead < 1 );

CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
NSDictionary *responseHeaders = (NSDictionary*)CFHTTPMessageCopyAllHeaderFields(response);
[responseHeaders autorelease];

if(cookies) [cookies release];
cookies = [[NSHTTPCookie cookiesWithResponseHeaderFields:responseHeaders forURL:self.address] mutableCopy];

if(self.logXMLInOut) {
NSLog(@"ResponseHeaders:\n%@", responseHeaders);
NSLog(@"ResponseBody:\n%@", responseBody);
}

return responseBody;
}
@end
@implementation sendSmsSoap_SendSms
@synthesize binding;
@synthesize response;
@synthesize parameters;
- (id)initWithBinding:(sendSmsSoap *)aBinding
parameters:(sendSms_SendSms *)aParameters
{
if((self = [super init])) {
response = nil;

self.binding = aBinding;

self.parameters = aParameters;
}

return self;
}
- (void)dealloc
{
if(binding != nil) [binding release];
if(parameters != nil) [parameters release];

[super dealloc];
}
- (void)main
{
[response autorelease];
response = [sendSmsSoapResponse new];

sendSmsSoap_envelope *envelope = [sendSmsSoap_envelope sharedInstance];

NSMutableDictionary *headerElements = nil;
headerElements = [NSMutableDictionary dictionary];

NSMutableDictionary *bodyElements = nil;
bodyElements = [NSMutableDictionary dictionary];
if(parameters != nil) [bodyElements setObject:parameters forKey:@"SendSms"];

NSString *operationXMLString = [envelope serializedFormUsingHeaderElements:headerElements bodyElements:bodyElements];

NSLog(@" operationXMLString %@", operationXMLString);

NSString *responseBody = [binding sendHTTPCallUsingBody:operationXMLString soapAction:@"http://FreebieSMS.co.uk/SendSms"];

NSLog(@" sendSmsSoap_SendSms main responseBody %@", responseBody);

xmlDocPtr doc;
xmlNodePtr cur;

const char *buffer = [responseBody cStringUsingEncoding:NSUTF8StringEncoding];

doc = xmlParseMemory(buffer, [responseBody length]);

NSAssert(doc != NULL, @"Errors while parsing returned XML");

cur = xmlDocGetRootElement(doc);
cur = cur->children;

for( ; cur != NULL ; cur = cur->next) {
if(cur->type == XML_ELEMENT_NODE) {

if(xmlStrEqual(cur->name, (const xmlChar *) "Body")) {
NSMutableArray *responseBodyParts = [NSMutableArray array];

xmlNodePtr bodyNode;
for(bodyNode=cur->children ; bodyNode != NULL ; bodyNode = bodyNode->next) {
if(cur->type == XML_ELEMENT_NODE) {
if(xmlStrEqual(bodyNode->name, (const xmlChar *) "SendSmsResponse") || xmlStrEqual(bodyNode->name, (const xmlChar *) "Fault") ) {
sendSms_SendSmsResponse *bodyObject = [sendSms_SendSmsResponse deserializeNode:bodyNode];
NSAssert1(bodyObject != nil, @"Errors while parsing body %s", bodyNode->name);
[responseBodyParts addObject:bodyObject];

} else {

NSLog(@" xml str no SendSmsResponse nor Fault %s", bodyNode->name );
}
}
}

response.bodyParts = responseBodyParts;
}
}
}

xmlFreeDoc(doc);

xmlCleanupParser();
}
@end
static sendSmsSoap_envelope *sendSmsSoapSharedEnvelopeInstance = nil;
@implementation sendSmsSoap_envelope
+ (sendSmsSoap_envelope *)sharedInstance
{
if(sendSmsSoapSharedEnvelopeInstance == nil) {
sendSmsSoapSharedEnvelopeInstance = [sendSmsSoap_envelope new];
}

return sendSmsSoapSharedEnvelopeInstance;
}
- (NSString *)serializedFormUsingHeaderElements:(NSDictionary *)headerElements bodyElements:(NSDictionary *)bodyElements
{
NSMutableString *serializedForm = [NSMutableString string];

[serializedForm appendFormat:@"\n"];
[serializedForm appendFormat:@" [serializedForm appendFormat:@"xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xsl:version=\"1.0\"\n"];
[serializedForm appendFormat:@"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"];
[serializedForm appendFormat:@"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n"];
[serializedForm appendFormat:@"xmlns:sendSms=\"http://FreebieSMS.co.uk\""];
[serializedForm appendFormat:@">\n"];

if(headerElements != nil) {
[serializedForm appendFormat:@"\n"];

for(NSString *key in [headerElements allKeys]) {
id header = [headerElements objectForKey:key];
NSString *elementName = [NSString stringWithFormat:@"%@:%@", [header nsPrefix], key];

[serializedForm appendFormat:@"%@\n", [header serializedFormUsingElementName:elementName]];
}

[serializedForm appendFormat:@"
"];
}

if(bodyElements != nil) {
[serializedForm appendFormat:@"\n"];

for(NSString *key in [bodyElements allKeys]) {
id body = [bodyElements objectForKey:key];
NSString *elementName = [NSString stringWithFormat:@"%@:%@", [body nsPrefix], key];

[serializedForm appendFormat:@"%@\n", [body serializedFormUsingElementName:elementName]];
}

[serializedForm appendFormat:@"
\n"];
}

[serializedForm appendFormat:@"
"];

return serializedForm;
}
@end
@implementation sendSmsSoapResponse
@synthesize headers;
@synthesize bodyParts;
- (id)init
{
if((self = [super init])) {
headers = nil;
bodyParts = nil;
}

return self;
}
@end
@implementation sendSmsSoap12
@synthesize address;
@synthesize logXMLInOut;
- (id)init
{
if((self = [super init])) {
address = nil;
cookies = nil;
logXMLInOut = NO;
}

return self;
}
- (id)initWithAddress:(NSString *)anAddress
{
if((self = [self init])) {
self.address = [NSURL URLWithString:anAddress];
}

return self;
}
- (void)addCookie:(NSHTTPCookie *)toAdd
{
if(toAdd != nil) {
if(cookies == nil) cookies = [[NSMutableArray alloc] init];
[cookies addObject:toAdd];
}
}
- (sendSmsSoap12Response *)SendSmsUsingParameters:(sendSms_SendSms *)aParameters
{
sendSmsSoap12_SendSms *operation = [(sendSmsSoap12_SendSms*)[sendSmsSoap12_SendSms alloc] initWithBinding:self
parameters:aParameters
];

NSOperationQueue *queue = [[NSOperationQueue new] autorelease];

[queue addOperation:operation];

[queue waitUntilAllOperationsAreFinished];

return operation.response;
}
- (NSString *)sendHTTPCallUsingBody:(NSString *)outputBody soapAction:(NSString *)soapAction
{
NSMutableDictionary *HTTPHeaders = [NSMutableDictionary dictionary];
if(cookies != nil) {
NSDictionary *fCookies = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
[HTTPHeaders addEntriesFromDictionary:fCookies];
}
[HTTPHeaders setObject:@"wsdl2objc" forKey:@"UserAgent"];
[HTTPHeaders setObject:soapAction forKey:@"SOAPAction"];

CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)@"POST", (CFURLRef)self.address, kCFHTTPVersion1_1);

CFDataRef bodyData = (CFDataRef)[outputBody dataUsingEncoding:NSUTF8StringEncoding];
CFHTTPMessageSetBody(request, bodyData);

for(NSString *key in [HTTPHeaders allKeys]) {
CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)key, (CFStringRef)[HTTPHeaders objectForKey:key]);
}

NSDictionary *outputHeaders = (NSDictionary*)CFHTTPMessageCopyAllHeaderFields(request);

if(self.logXMLInOut) {
NSLog(@"OutputHeaders:\n%@", outputHeaders);
NSLog(@"OutputBody:\n%@", outputBody);
}

CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);

if(!CFReadStreamOpen(readStream)) {
CFStreamError myErr = CFReadStreamGetError(readStream);
// An error has occurred.
if (myErr.domain == kCFStreamErrorDomainPOSIX) {
// Interpret myErr.error as a UNIX errno.
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
// Interpret myErr.error as a MacOS error code.
//OSStatus macError = (OSStatus)myErr.error;
// Check other error domains.
}
}

CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue);

//CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
//NSString *statusLine = (NSString*)CFHTTPMessageCopyResponseStatusLine(response);

NSMutableString *responseBody = [NSMutableString string];

static unsigned int kReadBufSize = 1024;
CFIndex numBytesRead;
do {
UInt8 buf[kReadBufSize];
numBytesRead = CFReadStreamRead(readStream, buf, sizeof(buf));
if( numBytesRead > 0 ) {
[responseBody appendString:[[[NSString alloc] initWithBytes:buf length:numBytesRead encoding:NSUTF8StringEncoding] autorelease]];
} else if( numBytesRead < 0 ) {
//CFStreamError error = CFReadStreamGetError(readStream);
//[[NSApplication sharedApplication] presentError:(NSError*)error];
}
} while( numBytesRead > 0 );

CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
NSDictionary *responseHeaders = (NSDictionary*)CFHTTPMessageCopyAllHeaderFields(response);
[responseHeaders autorelease];

if(cookies) [cookies release];
cookies = [[NSHTTPCookie cookiesWithResponseHeaderFields:responseHeaders forURL:self.address] mutableCopy];

if(self.logXMLInOut) {
NSLog(@"ResponseHeaders:\n%@", responseHeaders);
NSLog(@"ResponseBody:\n%@", responseBody);
}

return responseBody;
}
@end
@implementation sendSmsSoap12_SendSms
@synthesize binding;
@synthesize response;
@synthesize parameters;
- (id)initWithBinding:(sendSmsSoap12 *)aBinding
parameters:(sendSms_SendSms *)aParameters
{
if((self = [super init])) {
response = nil;

self.binding = aBinding;

self.parameters = aParameters;
}

return self;
}
- (void)dealloc
{
if(binding != nil) [binding release];
if(parameters != nil) [parameters release];

[super dealloc];
}
- (void)main
{
[response autorelease];
response = [sendSmsSoap12Response new];

sendSmsSoap12_envelope *envelope = [sendSmsSoap12_envelope sharedInstance];

NSMutableDictionary *headerElements = nil;
headerElements = [NSMutableDictionary dictionary];

NSMutableDictionary *bodyElements = nil;
bodyElements = [NSMutableDictionary dictionary];
if(parameters != nil) [bodyElements setObject:parameters forKey:@"SendSms"];

NSString *operationXMLString = [envelope serializedFormUsingHeaderElements:headerElements bodyElements:bodyElements];

NSString *responseBody = [binding sendHTTPCallUsingBody:operationXMLString soapAction:@"http://FreebieSMS.co.uk/SendSms"];

xmlDocPtr doc;
xmlNodePtr cur;

const char *buffer = [responseBody cStringUsingEncoding:NSUTF8StringEncoding];

doc = xmlParseMemory(buffer, [responseBody length]);

NSAssert(doc != NULL, @"Errors while parsing returned XML");

cur = xmlDocGetRootElement(doc);
cur = cur->children;

for( ; cur != NULL ; cur = cur->next) {
if(cur->type == XML_ELEMENT_NODE) {

if(xmlStrEqual(cur->name, (const xmlChar *) "Body")) {
NSMutableArray *responseBodyParts = [NSMutableArray array];

xmlNodePtr bodyNode;
for(bodyNode=cur->children ; bodyNode != NULL ; bodyNode = bodyNode->next) {
if(cur->type == XML_ELEMENT_NODE) {
if(xmlStrEqual(bodyNode->name, (const xmlChar *) "SendSmsResponse")) {
sendSms_SendSmsResponse *bodyObject = [sendSms_SendSmsResponse deserializeNode:bodyNode];
NSAssert1(bodyObject != nil, @"Errors while parsing body %s", bodyNode->name);
[responseBodyParts addObject:bodyObject];
}
}
}

response.bodyParts = responseBodyParts;
}
}
}

xmlFreeDoc(doc);

xmlCleanupParser();
}
@end
static sendSmsSoap12_envelope *sendSmsSoap12SharedEnvelopeInstance = nil;
@implementation sendSmsSoap12_envelope
+ (sendSmsSoap12_envelope *)sharedInstance
{
if(sendSmsSoap12SharedEnvelopeInstance == nil) {
sendSmsSoap12SharedEnvelopeInstance = [sendSmsSoap12_envelope new];
}

return sendSmsSoap12SharedEnvelopeInstance;
}
- (NSString *)serializedFormUsingHeaderElements:(NSDictionary *)headerElements bodyElements:(NSDictionary *)bodyElements
{
NSMutableString *serializedForm = [NSMutableString string];

[serializedForm appendFormat:@"\n"];
[serializedForm appendFormat:@" [serializedForm appendFormat:@"xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xsl:version=\"1.0\"\n"];
[serializedForm appendFormat:@"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"];
[serializedForm appendFormat:@"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n"];
[serializedForm appendFormat:@"xmlns:sendSms=\"http://FreebieSMS.co.uk\"\n"];
[serializedForm appendFormat:@">\n"];

if(headerElements != nil) {
[serializedForm appendFormat:@"\n"];

for(NSString *key in [headerElements allKeys]) {
id header = [headerElements objectForKey:key];
NSString *elementName = [NSString stringWithFormat:@"%@:%@", [header nsPrefix], key];

[serializedForm appendFormat:@"%@\n", [header serializedFormUsingElementName:elementName]];
}

[serializedForm appendFormat:@"
"];
}

if(bodyElements != nil) {
[serializedForm appendFormat:@"\n"];

for(NSString *key in [bodyElements allKeys]) {
id body = [bodyElements objectForKey:key];
NSString *elementName = [NSString stringWithFormat:@"%@:%@", [body nsPrefix], key];

[serializedForm appendFormat:@"%@\n", [body serializedFormUsingElementName:elementName]];
}

[serializedForm appendFormat:@"
\n"];
}

[serializedForm appendFormat:@"
"];

return serializedForm;
}
@end
@implementation sendSmsSoap12Response
@synthesize headers;
@synthesize bodyParts;
- (id)init
{
if((self = [super init])) {
headers = nil;
bodyParts = nil;
}

return self;
}
@end

Wednesday, June 10, 2009

Launching application via URL scheme


Launching application via URL scheme


Here I will try to explain how to make your application launch another application on the system. There will be a minimal code written for these feature like everything else in Objective C and Cocoa Touch framework. Application that have support for URL’s can be launched with a call to the UIApplication’s openURL:.

Everything will work fine if the URL is well formed and the application is properly registered. We’ll do that later. iPhone OS will take care of the rest. For example:

1.- (IBAction) someButton {
2.
3.[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://inchoo.net"]];
4.
5.}

This code above will run Safari browser and our site will pop up. There is several predefined URL schemes for integrated iPhone OS applications such as Mail. If you decide that you want launch another application (for testing purpose) from your application, you must first register URL scheme of application that is going to be launched. That is easy part of job. To register a custom URL scheme, just add a this in Info.plist.

infoplist1

When we have done that, we just implement this code in method that triggers our button from nib file.

1.- (IBAction) anotherButton {
2.
3.[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"myapp://"]];
4.
5.}

And now we can launch this application from our application. This is very simple and easy to implement so try it!


Copy from here