新手新手炒白银怎么开户点~~~~~!!!!!!!!

更多选车参考:
综述:各位朋友好:我是一个1.6的车主,我经常留意千里马的论坛,想从中了解一些用车的心得什么的,可是这类的文章很少,老是讨论一些不着边际话题,(这车好还是坏)抱歉,这话有的重,因为我人较直。我认为对车的认识是每个人有不同,不能强求别人和你一样,还有车的好还是坏并不是光说就可以说明白的,有的人喜力性好的,有人喜欢车厢大一点等等,要想都好我想10万是不够的。
我来说说我感受,我是03年买的,到现在大约是30000多公里了,5000公里作一次保养(到4S店做),车是没什么毛病,就是感觉油漆嫩的,再说我一开始新手上路,油漆补了好几次。我感觉这车的还是不错的,有人说他起步慢,我不知是怎么开的,是不是原来开大的车,起步不用加油啊。这小排量的车起步在半离合时要催油,不用催很大,(我几个朋友有派力噢1.3自动档、1。6手动档、手动档,自动档我不说了,其他的起步都要催油啊,我自己开过他们的车),这样起步就不慢了。关于的问题新手和老手,期和磨出的是不一样,因此关于这个问题很难说,我自己是个半新半旧手,城市车多的话9左右,跑高速的话6不到点(我跑杭甬高速一年多),你们自己算把,至于车子高速时有的飘的问题是有,但很怪,120开始飘,到140车子就不飘了,不要以为我开快,一次我和朋友一起手势看错了,变成飚车了,开到160,差点出车祸,两人自己都不肯让啊,现在想一想后怕啊,劝朋友们不要开快车,手势要看清。
希望多看到一些使用的心得,大家交流一下,谢谢!!!
20:50:48回复(0)|支持(1)
上一条口碑:
下一条口碑:
车型评分:*
做出个总体评价吧
评价标题:*
必填,3-20个汉字
您的评价会对其他人有很大的帮助
填写个综述吧10-500汉字
您还需要输入10个汉字
选择口碑分类:
外观内饰操控动力售后保养
请输入验证码:
验证码有误
同步到微博&&
指导价:暂无(待定)
市场价: 暂无
类型:小型
保修:3年/5万公里
擅长领域:
解答问题:个
被提问:次> 新手上路全攻略开车技巧汇编,新手开车哪些注意事项? - 文章正文
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《新手上路全攻略开车技巧汇编》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!
  一、新车磨合需要注意的问题
  新车首先要注意的是磨合,因为汽车磨合的好坏会对汽车的寿命、安全性和燃油经济性等方面产生较大的影响。在新车磨合的时候一般需要注意以下几点:
  1.无论是新车还是旧车,汽车启动都需要预热,而且非常有必要。因为刚启动的发动机温度低,各部位的润滑油还没到位,立即开车会让互相接触的部件得不到充分的润滑,致使零部件损耗。但如果长时间&预热&不但会让发动机产生大量积碳,而且也不利于环保,所以建议大家在启动车辆10秒钟左右就可以出发了,也就相当于是系好安全带,整理整理衣服的时间。
  另外,&热车&也有季节之分,比如冬天的时候气温很低,这时怠速时间就可以稍微长一些,一般在30秒左右就可以了,然后可以采用低速行驶1~2公里的方法继续预热,这样就可以避免长时间怠速所产生的负面效果了。
  2.避免负荷过重。在磨合期间的车辆,发动机内的零件仍然处于&崩紧&的状态,如果整天是满载运行的话,那会对机件造成一定的损坏。
  3.忌长途行驶和高速行驶。长途旅行也就意味着发动机连续长时间工作,这对发动机内部仍没&沟通&好的零件来说是一个负荷,会直接影响到零件之间的配合,不利于发动机长期的使用。
  另外,处在磨合期的汽车,最好避免高速行驶。据资料显示,新车在磨合期内速度最好控制在40-70公里/小时内,不能以过高的速度行驶。在行驶的过程中,还需要注意发动机转速表,磨合期的发动机的最高转速值建议保持在转/分。
  4.使用品质较好的燃油。其实不管是新车,还是旧车,它们都不能使用低于厂家规定标号的燃油(标号一般在油箱盖上)。这对于仍处在磨合期的新车来说更为重要,如果条件允许的话,尽量使用品质较好、标号较高的燃油。最好也别添加抗磨损的添加剂,这类添加剂的广告总说得很美,但实质上起不到太大的效用,加了添加剂还有可能出现里程数已够而磨合不足的现象。
  5.换挡需要及时,这个主要是针对新手和使用手动挡车型的朋友来说的。及时换挡是为了避免高挡位低转速和低挡位高转速行驶的情况,这对发动机的长期使用来说都是不好的。也不要长时间用着一个挡位,该升挡就升挡,该降挡就降挡,不要每一次都到达挡位的最高速度才进行切换。
  另外,自动挡也需要磨合。建议的方法是可以先将挡位挂到低挡位,然后让发动机转速提到是中高段,保持20-30秒,时间不要过长,转速也不能过高。然后,放开油门主动让车速和转速降低,此后每一个挡位都用这种方法进行适当的磨合。至于手自一体变速箱,则可以切换到手动模式,然后按照上面的方法,每个挡位进行磨合。
  6.刹车系统需要磨合。在新车磨合期的时候,切忌猛踩刹车,缓慢刹车可以让新车的刹车鼓或刹车片取得一个更好的配合间隙。
  7.切忌时常紧急制动。不管是新车还是老车,紧急制动可以避免的话就尽量避免,因为每一次紧急制动都会给刹车系统带来强大的负荷,不仅对刹车系统有损害,而且还增加了危险性。为了避免紧急刹车的发生,开车时最好确定一个安全的距离,在这个安全距离内便开始缓慢刹车。换句话说,就是在确保安全的前提下尽量让车子可以缓慢地停下来。
  二、驾驶姿势直接影响到驾驶的安全
  正确的驾驶姿势对行车的安全也是十分重要,看似平常的事儿但在紧急关头它可能会成为你的&救命稻草&。正确的驾驶姿势就像儿时学习写字一样,如果基础没有打好,那将会带来很多不良的后果。对于刚接触汽车的新手,在这个时候如果没有一个正确的驾驶姿势,严重点说会影响到你日后驾驶的习惯。
  误区:驾驶姿势不正确最常见的现象是座椅过于靠前,这现象新手尤为明显。作为新手开车上路,他们都不由得有点紧张,于是他们的潜意识会认为越贴近方向盘,脚越靠近踏板会更加安全一些。另一种常见的错误姿势自然是座椅相对靠后了,这种现像常会出现在长得高大的新手里面。由于身材高大,车舱的空间也有限,因此他们会有一些压抑感,这个时候为了大长腿能够得到伸展,他们会把座椅调校得十分靠后,看上去是十分安逸的感觉,不过其实是暗藏危机。
  正确的驾驶坐姿应该是:在坐进驾驶席之后,应深深地坐在座椅后部,腰部和肩部靠在椅背,手臂伸向前方,可以自然握住转向盘前段。同时,手腕能自由地弯曲,活动自由;右脚轻放刹车踏板,大小腿间角度应为钝角约120度左右或更大一些,但紧踩时大小腿不能完全呈直线,用脚踩离合器踏板、制动踏板或油门时不费力,身体不能前倾。
  三、安全意识对驾驶十分重要
  我们开车无疑是为了让生活更加便捷,但安全同样是绝对不能松懈的。既然这样,我在这里就简单地提几点关于安全意识方面的小知识,对于新老手同样适用。
  1.开车时切忌打手机。有资料显示,开车打手机的人的思维能力和判断能力只是正常时候的1/3。生命仅是一念之差,有的时候多一秒钟就可以活命。为了你和他人的安全,开车时切勿打手机!
  2.开车应保持安全距离和尽量少用急刹车,谨防追尾和被追尾。不管是追尾,还是被人追尾,其实都是身不由己。如果想避免这样的事情发生,那不妨尝试一下下面的技巧:首先,开车时尽量与前车保持一定的距离,刹车时尽量避免急刹,以给后车留下充足的反应时间;其次,遇黄灯时,切忌加速以图通过,应提前刹车让车子可以缓慢停下来。
  3.适当使用远光灯。没错,远光灯的确是让你在晚上可以看得更远,不过随意使用的话带来的危险会更大。其实国家交通法对远近光灯的使用有明确的规定,违反了规定你有可能会吃上罚单。
  我国《道路交通安全法》第四十八条规定:在没有中心隔离设施或者没有中心线的道路上,夜间会车应当在距相对方向来车150米以外改用近光灯,在窄路、窄桥与非机动车会车时应当使用近光灯;机动车在夜间没有路灯、照明不良或者遇有雾、雨、雪、沙尘、冰雹等低能见度情况下行驶时,同方向行驶的后车与前车近距离行驶时,应使用近光灯;机动车在夜间通过急弯、坡路、拱桥、人行横道或者没有交通信号灯控制的路口时,应当交替使用远近光灯示意。夜间在没有照明条件的道路行车,当车速低于每小时30公里时,可以使用近光灯;当车速高于每小时30公里时,可以使用远光灯。夜间车辆通过照明条件好的路段,应该使用近光灯。
  四、手动或自动变速箱的使用
  手动挡驾驶技巧
  1.不要繁频踩离合。习惯性踩离合器不但对压盘压片不好,而且影响行车安全。起步是需要慢抬离合,车辆行驶时应彻底松开离合。切忌一边踩刹车,一边踩离合。
  2.不一味追求高挡位。开车并不用追求高挡位。每个挡位都有自己的功能。一般情况下,1挡起步。遇雪天或是路面十分湿滑的情况,可以适当使用2挡起步,以防止1挡起步时高扭力输出致使打滑情况增加。
  3.换挡技巧。一般市区行驶时,换挡的转速最好保持在2500转/分以上。低转速换挡燃油经济性或许会好一点,不过这对发动机来说也并非好事。例如,如果在2000转左右就进行换挡操作的话,那换挡后发动机转速很自然就会降到1000多转了,转速过低,发动机扭矩输出比较憋屈,这容易产生积碳。
  4.换挡时的正确操作。在行车中换挡时,操纵离合器踏板应迅速踩下并抬起,不要出现半联动现象,否则,会加速离合器的磨损。
  自动挡驾驶技巧
  自动变速箱的出现让驾驶变得更轻松自如,可能你会觉得自动挡的使用根本不需要讨论。其实不然,自动挡的使用也有需要注意的事情。
  1.自动挡车辆不能空挡滑行。在空挡下,自动挡车型的自动变速器里的齿轮会在车轮带动下高速运转。由于变速器油泵供油不足,齿轮容易因为得不到充分的润滑而烧蚀,也容易使自动变速器油温过高而影响使用寿命。
  2.自动挡车在行驶中切忌推入P挡。在从倒挡挂入前进挡或前进挡挂入倒挡时,一定要等车辆停稳后再做操作。
  3.临时停车的问题。另外关于临时停车(如等红灯)时,自动挡到底该用N挡还是D挡这个问题一直有些争论,其实用N或者D挡都没有错,只是自己的习惯而已。暂时停车挂在D挡对车子并没有损害,因为变速器内扭力转换器设有一组附有单向离合器的反应轮,其作用是放大来自发动机曲轴的扭力,在发动机怠速下它是不会转动的,只有待发动机转速上升时它才会起作用。所以,我的建议是如果停车超过半分钟,你可以挂入N挡,如果停车时间很短的话就直接踩着刹车便可。
  4.自动挡车型爬坡时遇到的问题。使用D挡爬坡时,如果感觉到怎样踩油门也不能使发动机输出的动力像行驶在平坦路面一样强劲或是动力已经显得不足的时候,应当先把速度降下来,然后把挡位切换到扭力相对较高的挡位。这样不仅省油,还能减少或避免发动机的磨损。部分4AT变速箱会配有O/D按钮,这个时候需要先降低速度,然后按着O/D按钮才可以切换到高扭力的低速挡位。
  5.拖车应该注意事项。自动挡的车在拖车的时候需要注意,拖车总距离不能超过80公里,速度不大于30公里/小时,拖车的时候要让车的驱动轮离开地面。另外,除了属于分时四驱的四驱车以外,其他的四驱车不能直接拖走,这时候可以借助其他工具(或直接用平板车运走),让四驱车的四个轮离开地面。
  五、停车入位的技巧
  停车入位也是一个让新手较为头痛的问题。在停车方面,主要有&非&字形停车入位和侧方停车入位。如果遇到&非&字形停车入位,基本方法为将车开至所要停放车位的间隔车位前方,并间隔1.5米。随后,打满方向缓慢倒车将车倒车入位。
  如遭遇侧方停车入位,则需将车开于所要停放车位前方车辆平行处(车灯对应于对方车辆的B柱),并间隔30-40厘米。随后,方向往右打满,开始倒入停车位。当车头跟前车车尾的连线达到与车位垂直时,再向左打满缓慢倒入。
  最后,我要说的是,车开得快,并不代表你就是&汽车驾驶达人&,真正的达人不仅要有精湛的驾驶技术,还需要有优秀的安全意识和驾驶素质。如果你能真正做到以上几点,那下一个&汽车驾驶达人&将会是你。
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《新手上路通过窄道技巧》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!所以我们在通过这些窄道时,先弄清楚那些水泥墩的位置了,再打方向盘转向,不然就很容易给爱车造成不必要的伤害。总结:日常行车中,在通过这些窄道、窄门时发生刮刮蹭蹭是件挺郁闷的事,尤其对于新手来说更是这样。不过在通过这些
/XinShouJiaZhao/YSDB47897.html
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《新手上路之夜间行车注意事项》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!1.会车注意右侧非机动车夜间会车不要手忙脚乱、一会儿踩制动踏板、一会儿向右打轮,要注意右侧行人和自行车。与对向车相距150米时,应将远光灯变为近光灯。这既是行车礼貌也是行车安全的保证。当遇对方不改用近光,应立
/XinShouJiaZhao/YSDB47896.html
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《高速违章免扣分大法》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!&史上最严交规&的实施令不少车主&压力山大&,闯红灯扣6分、遮挡号牌记12分&&一年下来,驾照上的12分显得尤其&金贵&
/XinShouJiaZhao/YSDB47895.html
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《汽车安全带的正确使用方法》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!汽车安全带是为了在碰撞时对乘员进行约束以及避免碰撞时乘员与方向盘及仪表板等发生二次碰撞或避免碰撞时冲出车外导致死伤的安全装置。汽车安全带又可以称之为座椅安全带,是乘员约束装置的一种。汽车安全带是公认的最廉价也是
/XinShouJiaZhao/YSDB47243.html
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《女司机新手上路指南》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!1、驾驶习惯提醒:省油可以做到面对爱车,女司机一方面要细心,不能马虎大意,另外一方面也需要掌握一些要领,不但可以省油,也有利于保养爱车。忘记放手刹手刹一般用于停车制动,不少女新手往往不放手刹匆匆上路。汽车行驶面对着刹
/XinShouJiaZhao/YSDB47239.html
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《新手上路必备换挡技巧》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!●牢记挡位图手动挡车的挡位分布就那几种,当你坐在驾驶座上,第一眼就应该扫描变速杆手把上的挡位图,(我的诀窍就是记住1挡和倒挡位置即可)。切记开车时不能低头看变速杆换挡,特别是在市区和高速时,低头换挡容易造成车辆跑偏
/XinShouJiaZhao/YSDB47238.html
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《新手上路开自动挡的注意事项》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!空档不省油、别挂空档滑行很多以前驾驶手动档车型的老司机们,都有挂空档滑行的驾驶习惯,按照当年老司机们的说法:虽危险但省油。可现在请一定要记住,自动档汽车挂空档滑行不仅不省油而且还会对变速箱造成损伤。还有一种情
/XinShouJiaZhao/YSDB47236.html
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《新手上路驾车十大禁忌》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!禁忌一:忘记检查轮胎技巧:出行前四个轮胎都要仔细检查一遍,最好到专业维修店调整好轮胎气压。尤其不要忘记检查备胎,看是否完好有气。中途休息时,也要检查轮胎,用拳头敲打一下,看是否正常。如果有漏气,要立即修补。一旦行驶
/XinShouJiaZhao/YSDB47235.html
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《新手上路基本交规大全》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!&新手不能独自上高速法律规定:在实习期内驾驶机动车上高速公路时,必须由持相应或者更高车型驾驶证3年以上的驾驶人陪同。小编提醒:刚拿驾照一年内为实习期,除了要求在车背后贴上&实习&rdquo
/XinShouJiaZhao/YSDB47234.html
驾照考试新手上路是由月亮岛教育网jisiedu小编整理的,下面我们看看《新手上路超车技巧及自动挡车驾驶技巧》,希望能帮助到您。本文来源于网络,仅供驾驶学习使用!工具/原料性能良好的自动挡车。步骤/方法起步技巧。自动挡车起步时需注意,汽车发动前,要确保挡靶子在P挡或N挡上,起步时注意刹车、手刹和油门应配合好,挂上D挡后,松手刹的同时慢抬刹车(等同于手动挡车的慢
/XinShouJiaZhao/YSDB46578.html
本栏目新最资讯TOP20
城市分站加盟1119人阅读
http://lianxu.me/blog//10-cocoa-objc-newbie-problems/
首先请谅解我可能使用很多英文,毕竟英文资料将来会是你的主要资料来源。
在你继续深入学习之前,请停下脚步弄清这些问题。如果你是新手,这个教程不要希望一次能看的非常透彻,学一定阶段反回来再看看又会有新的体会的。对于完全看不懂的同学,也不要强求自己。找来《计算机组成原理》《数据结构》《操作系统》《编译原理》《计算机网络》之类的大学课本看看吧。这些基础不可能在这个论坛学到的,至少不可能系统的学到。
1. language background
首先c, c++语言背景,必须。
很多人问 “没有任何语言基础,我不想学c直接学objective-c”
这里简单几句,objc 90%代码是c、众多开源代码是c,c++。你不学好c在unix世界里只能是个二流开发者!也许说得过于严厉,不过自己斟酌把。
接着English必须。
需要英语!需要英语!需要英语!苹果不会把它们文档都写成中文的。“什么,有人翻译?” 等有人闲着翻译出来了的时候,大家都已经卖了很多软件了。你也是跟着人家屁股后面做开发。
2. Runtime(运行时)
Objective-c是动态语言, 很多新手或者开发人员常常被Runtime这个东西所迷惑。而恰恰这是一个非常重要的概念。 为什么重要呢!?我可以这么问:“如果让你(设计、)实现一个计算机语言,你要如何下手?” 很少程序员这么思考过。但是这么一问,就会强迫你从更高层次思考(1)以前的问题了。 注意我这句话‘设计’括起来了,稍微次要点,关键是实现。
我把实现分成3钟不同的层次:
1. 传统的面向过程的语言开发,例如c语言。实现c语言编译器很简单,只要按照语法规则实现一个LALR语法分析器就可以了,编译器优化是非常难的topic,不在这里讨论范围内,忽略。 这里我们实现了编译器其中最最基础和原始的目标之一就是把一份代码里的函数名称,转化成一个相对内存地址,把调用这个函数的语句转换成一个jmp跳转指令。在程序开始运行时候,调用语句可以正确跳转到对应的函数地址。 这样很好,也很直白,但是。。。太死板了。everything is pre-determined
2. 我们希望灵活,于是需要开发面向对象的语言,例如c++。 c++在c的基础上增加了类的部分。但这到底意味着什么呢?我们再写它的编译器要如何考虑呢?其实,就是让编译器多绕个弯,在严格的c编译器上增加一层类处理的机制,把一个函数限制在它处在的class环境里,每次请求一个函数调用,先找到它的对象, 其类型,返回值,参数等等,确定了这些后再jmp跳转到需要的函数。这样很多程序增加了灵活性同样一个函数调用会根据请求参数和类的环境返回完全不同的结果。增加类机制后,就模拟了现实世界的抽象模式,不同的对象有不同的属性和方法。同样的方法,不同的类有不同的行为!
这里大家就可以看到作为一个编译器开发者都做了哪些进一步的思考。但是。。。还是死板, 我们仍然叫c++是static language。
3. 希望更加灵活! 于是我们完全把上面哪个类的实现部分抽象出来,做成一套完整运行阶段的检测环境。这次再写编译器甚至保留部分代码里的sytax名称,名称错误检测,runtime环境注册所以全局的类,函数,变量等等信息等等,我们可以无限的为这个层增加必要的功能。调用函数时候,会先从这个运行时环境里检测所以可能的参数再做jmp跳转。这,就是runtime。编译器开发起来比上面更加弯弯绕。但是这个层极大增加了程序的灵活性。 例如当调用一个函数时候,前2种语言,很有可能一个jmp到了一个非法地址导致程序crash,
但是在这个层次里面,runtime就过滤掉了这些可能性。 这就是为什么dynamic langauge更加强壮。 因为编译器和runtime环境开发人员已经帮你处理了这些问题。
好了上面说着这么多,我们再返回来看objective-c. 现在你是不是能理解这样的语句了呢?
if ([obj respondsToSelector:@selector(function1:)) {
if ([obj isKindOfClass:[NSArray class]] ) {
if ([obj conformsToProtocol:@protocol(myProtocol)]) {
if ([[obj class] isSubclassOfClass:[NSArray class]]) {
[obj someNonExistFunction];
看似很简单的语句,但是为了让语言实现这个能力,语言开发者要付出很多努力实现runtime环境。这里运行时环境处理了弱类型、函数存在检查工作。runtime会检测注册列表里是否存在对应的函数,类型是否正确,最后确定下来正确的函数地址,再进行保存寄存器状态,压栈,函数调用等等实际的操作。
id knife=[Knife grateKnife];
NSArray *m*****terList=[NSArray array];
[m*****terList makeObjectsPerformSelector:@selector(killM*****ter:) withObject:knife];
用c,c++完成这个功能还是比较非常麻烦的,但是动态语言处理却非常简单并且这些语句让objc语言更加intuitive。
现在说一下runtime的负面影响:
1. 关于执行效率问题。 “静态语言执行效率要比动态语言高”,这句没错。因为一部分cpu计算损耗在了runtime过程中。而静态语言生成的机器指令更简洁。正因为知道这个原因,所以开发语言的人付出很大一部分努力为了保持runtime小巧上。所以objecitve-c是c的超集+一个小巧的runtime环境。 但是,换句话说,从算法角度考虑,这点复杂度不算差别的,Big O notation结果不会有差别。( It’s not log(n) vs n2 )
2. 另外一个就是安全性。动态语言由于运行时环境的需求,会保留一些源码级别的程序结构。这样就给破解带来的方便之门。一个现成的说明就是,java,大家都知道java运行在jre上面。这就是典型的runtime例子。它的执行文件.class全部可以反编译回近似源代码。所以这里的额外提示就是如果你需要写和安全有关的代码,离objc远点,直接用c去。
简单理解:“Runtime is everything between your each function call.”
但是大家要明白,第二点我提到runtime并不只是因为它带来了这些简便的语言特性。而是这些简单的语言特性,在实际运用中需要你从完全不同的角度考虑和解决问题。只是计算1+1,很多语言都是一样的,但是随着问题的复杂,项目的增长,静态语言和动态语言就会演化出完全不同的风景。
&thread synchronization another notorious trouble!&
记不记得上学时候学得操作系统这门课,里面都会有专门一章介绍任务调度和生产者消费者的问题。 这就是为了今后使用进程、线程开发打基础。概念很简单,但是心知肚明的人很少。难点在synchronization(同步),因为1. There is no 100% deadlock detection algorithm. If there is, no deadlock at all. 2. 往往这类错误很隐晦,静态分析很难找到。 3. 抽象度较高需要经验去把握。
总体来说,我见到的在这方面的问题可以分为一下几点:
1. 不知道多线程开发的几个基点,看别人代码越看越糊涂的。一会NSThread、一会Grand Central Dispatch、block等等。。。Apple封装了很多线程的api, down to core多线程的结构基本是:
可以看到在多线程开发中你可以选择这上面这4种不同的方式。
Mach是核心的操作系统部分。其实这个我也不是非常熟悉,至少我还没有读到过直接使用mach做多线程的代码。
pthread(POSIX Threads)是传统的多线程标准,灵活、轻巧,但是需要理论基础,开发复杂。需要注意一点,根据apple文档提示,在Cocoa下使用pthread需要先启动至少一个NSThread,确定进入多线程环境后才可以。
NSThread是Mac OS 10.0后发布的多线程API较为高层,但是缺乏灵活性,而且和pthread相比效率低下。
Grand Central Dispatch 是10.6后引入的开源多线程库,它介于pthread和NSThread之间。比NSThread更灵活、小巧,并且不需要像pthread一样考虑很多lock的问题。同时objective-c 2.0发布的新语法特性之一blocks,也正是根据Grand Central Dispatch需求推出的。
所以在你写多线程代码或者阅读多线程代码时候,心理要先明确使用哪种技术。
2. thread和Reference Counting内存管理造成的问题。
线程里面的方法都要放到NSAutoreleasePool里面吗这类问题很常见,主要原因是 NSAutoreleasePool 到底是干什么用得不明白。 NSAutoreleasePool跟thread其实关系并不显著,它提供一个临时内存管理空间,好比一个沙箱,确保不会有不当的内存分配泄露出来,在这个空间内新分配的对象要向这个pool做一下注册告诉:“pool,我新分配一块空间了”。当pool drain掉或者release,它里面分配过的内存同样释放掉。可见和thread没有很大关系。但是,我们阅读代码的时候经常会看到,新开线程的函数内总是以NSAutoreleasePool开始结束。这又是为什么呢!?
因为thread内恰好是最适合需要它的地方! 线程函数应该计算量大,时间长(supposed to be heavy)。在线程里面可能会有大量对象生成,这时使用autoreleasepool管理更简洁。所以这里的***是,不一定非要在线程里放NSAutoreleasePool,相对的在cocoa环境下任意地方都可以使用NSAutoreleasePool。如果你在线程内不使用NSAutoreleasePool,要记得在内部alloc和relase配对出现保证没有内存泄露。
3. 线程安全
每个程序都有一个主线程(main thread),它负责处理事件相应,和UI更新。
更新UI问题。很多新手会因为这个问题,导致程序崩溃或出现各种问题。而且逛论坛会看到所以人都会这么告诉你:“不要在后台线程更新你的UI”。其实这个说法不严密,在多线程环境里处理这个问题需要谨慎,而且要了解线程安全特性。
首先我们需要把“UI更新”这个词做一个说明,它可以有2个层次理解,首先是绘制,其次是显示。这里绘制是可以在任何线程里进行,但是要向屏幕显示出来就需要在主线程操作了。我举个例子说明一下,例如现在我们有一个NSImageView,里面设置了一个NSImage, 这时我想给NSImage加个变色滤镜,这个过程就可以理解为绘制。那么我完全可以再另外一个线程做这个比较费时的操作,滤镜增加完毕再通知NSImageView显示一下。另一个例子就是,Twitter客户端会把每一条微博显示成一个cell,但是速度很快,这就是因为它先对cell做了offscreen的渲染,然后再拿出来显示。
所以通过这点我们也可以得到进一步的认识,合理设计view的更新是非常重要的部分。很多新手写得代码片段没错,只是因为放错了地方就导致整个程序出现各种问题。
根据苹果线程安全摘要说明,再其它线程更新view需要使用lockFocusIfCanDraw和unlockFocus锁定,确保不会出现安全问题。
另外还要知道常用容器的线程安全情况。immutable的容器是线程安全的,而mutable容器则不是。例如NSArray和NSMutableArray。
5. Asynchronous(异步) vs. Synchronous(同步)
我在一个view要显示多张web图片,我想问一下,我是应该采用异步一个一个下载的方式,还是应该采用多线程同时下载的方式,还是2个都用,那种方式好呢?
实际上单独用这2个方法都不好。并不是简单的用了更多线程就提高速度。这个问题同时涉及客户端和服务器的情况。
处理这种类型的程序,比较好的结构应该是:非主线程建立一个队列(相当于Asynchronous任务),队列里同时启动n个下载任务(相当于Synchronous任务)。这里的n在2~8左右就够了。这个结构下可以认为队列里面每n个任务之间是异步关系,但是这n个任务之间又是同步关系,每次同时下载2~8张图片。这样处理基本可以满足速度要求和各类服务器限制。
(非常抱歉,之前质疑问问题的人理解错误。其实是我自己晕了,问得问题很好。)
4. runloop
现在说说runloop为何会成为cocoa开发中迷惑的点。因为很多新手没有从动态角度看它。 首先回想一下第2点介绍的runtime的概念。 接着我出一个题思考一下。
现在我有一个程序片段如下: 复制代码
- (void)myThread:(id)sender
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
while (TRUE) {
//do some jobs
//break in some condition
usleep(10000);
[pool drain];
[pool release];
现在要求,做某些设计,使得当这个线程运行的同时,还可以从其它线程里往它里面随意增加或去掉不同的计算任务。 这,就是NSRunloop的最原始的开发初衷。让一个线程的计算任务更加灵活。 这个功能在c, c++里也许可以做到但是非常难,最主要的是因为语言能力的限制,以前的程序员很少这么去思考。
好,现在我们对上面代码做一个非常简单的进化:
NSMutableArray *targetQ
NSMutableArray *actionQ
- (void)myThread:(id)sender
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
while (TRUE) {
//do some jobs
//break in some condition
int n=[targetQueue count];
assert(n==[actionQueue count]);
for(int i=0;i&n;i++){
id target=[targetQueue objectAtIndex:i];
SEL action=NSSelectorFromString([actionQueue objectAtIndex:i]);
if ([target respondsToSelector:action]) {
[target performSelector:action withObject:nil];
usleep(10000);
[pool drain];
[pool release];
注意,这里没有做线程安全处理,记住Mutable container is not thread safe.
这个简单的扩展,让我们看到了如何利用runtime能力让线程灵活起来。当我们从另外线程向targetQueue和actionQueue同时加入对象和方法时候,这个线程函数就有了执行一个额外代码的能力。
但,有人会问,哪里有runloop? 那个是 nsrunloop? 看不出来啊。 复制代码
while (TRUE) {
//break in some condition
一个线程内这个结构就叫线程的runloop, 它和NSRunloop这个类虽然名字很像,但完全不是一个东西。以前在使用静态语言开始时候,程序员没有什么迷惑,因为没有NSRunloop这个东西。 我接着来说,这个NSRunloop是如何来得。
第二段扩展代码里面确实没有NSRunloop这个玩意儿,我们接着做第3次改进。 这次我们的目的是把其中动态部分抽象出来。
@interface MyNSTimer : NSObject
CFAbsoluteT
@implementation MyNSTimer
if ([target respondsToSelector:action]) {
[target performSelector:action withObject:nil];
@interface MyNSRunloop : NSObject
NSMutableArray *timerQ
- (void)addTimer:(MyNSTimer*)t;
- (void)executeO
@implementation MyNSRunloop
- (void)addTimer:(MyNSTimer*)t;
@synchronized(timerQueue){
[timerQueue addObject:t];
- (void)executeO
CFAbsoluteTime currentTime=CFAbsoluteTimeGetCurrent();
@synchronized(timerQueue){
for(MyNSTimer *t in timerQueue){
if(currentTime-t.lasttime&t.interval){
t.lasttime=currentT
[t invoke];
@interface MyNSThread : NSObject
MyNSRunloop *
- (void)main:(id)
@implementation MyNSThread
- (void)main:(id)sender
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
while (TRUE) {
//do some jobs
//break in some condition
[runloop executeOnce];
usleep(10000);
[pool drain];
[pool release];
走到这里,我们就算是基本把Runloop结构抽象出来了。例如我有一个MyNSThread实例,myThread1。我可以给这个实例的线程添加需要的任务,而myThread1内部的MyNSRunloop对象会管理好这些任务。
MyNSTimer *timer1=[MyNSTimer scheduledTimerWithTimeInterval:1
target:obj1
selector:@selector(download1:)];
[myThread1.runloop addTimer:timer1];
MyNSTimer *timer2=[MyNSTimer scheduledTimerWithTimeInterval:2
target:obj2
selector:@selector(download2:)];
[myThread1.runloop addTimer:timer2];
当你看懂了上面的代码也许会感叹,‘原来是这么回事啊!为什么把这么简单的功能搞这么复杂呢?’ 其实就是这么回事,把Runloop抽象出来可以使得线程任务管理更加loose coupling,给设计模式提供更大的空间。这样第三方开发者不需要过深入的涉及线程内部代码而轻松管理线程任务。另外请注意,这里MyNSRunloop, MyNSTimer等类是我写得一个模拟情况,真实的NSRunloop实现肯定不是这么简单。这里只为了说明一个思想。这种思想贯穿整个cocoa framework从界面更新到event管理。
5. delegate, protocol
这个会列出来因为,我感觉问它的数量仅此于内存管理部分,它们用得很频繁,并且它们是多钟设计模式的重要组成部分。
6. event responder
使用过Xcode的开发者都知道Interface Builder这个开发组件,在Xcode4版本以后该组件已经和xcode整合到一起。它是苹果软件开发中非常重要的部分。ib为开发者减轻了很大一部分界面设计工作。但是其中有一个东西让新接触ib的开发者一头雾水,那就是First Responder, 它是什么东西,为何它会有那么多Acti*****。这节我会详细介绍如何理解Responder和Cocoa下的事件响应链。
First Responder在IB属性为Placeholders,这意味着它属于一个虚拟实例。就好比TextField里面的string placeholder一样,只是临时显示一下。真正的first responder会被其它对象代替。实际上,任何派生自NSResponder类的对象都可以替代First Responder。而First Responder里面的所有Acti*****就是NSResponder提供的接口函数,当然你也可以定义自己的响应函数。
MacOS在系统内部会维护一个称为“The Responder Chain”的链表。该列表内容为responder对象实例,它们会对各种系统事件做出响应。最上面的哪个对象就叫做first responder,它是最先接收到系统事件的对象。如果该对象不处理该事件,系统会将这个事件向下传递,直到找到响应事件的对象,我们可以理解为该事件被该这个对象截取了。
The Responder Chain基本结构如下图所示:
在理解了上面的概念之后,我希望使用一个例子让大家对responder有更加具体的认识。大家都知道NSTextField这个控件,它是最常见的控件之一。它最基本功能是显示一个字符串,如果启用可选,那么用户可以选中文本,拷贝文本,如果开启编辑选项,还可以运行用户编辑文本,等等基本操作。
下面展示给大家的例子是创建一个我们自己创建的简单textfield叫LXTextField。它不属于NSTextField而是派生自NSView,具有功能显示字符串,全选字符串,响应用户cmd+c的拷贝操作,三个基本功能。注意NSView派生自NSResponder。
@interface LXTextField : NSView
NSString *stringV
BOOL selectA
@property(retain,nonatomic) NSString *stringV
@implementation LXTextField
@synthesize stringV
- (void)awakeFromNib
selectAll = NO;
- (id)initWithFrame:(NSRect)frameRect
if( self = [super initWithFrame:frameRect] ){
selectAll = NO;
- (BOOL)acceptsFirstResponder
return YES;
- (BOOL)becomeFirstResponder
return YES;
- (BOOL)resignFirstResponder
selectAll=NO;
[self setNeedsDisplay:YES];
return YES;
- (void)setStringValue:(NSString *)string{
stringValue =
[self setNeedsDisplay:YES];
- (void)drawRect:(NSRect)dirtyRect
if (selectAll) {
NSRect r = NSZeroR
r.size = [stringValue sizeWithAttributes:nil];
[[NSColor selectedControlColor] set];
NSRectFill(r);
[stringValue drawAtPoint:NSZeroPoint withAttributes:nil];
- (IBAction)selectAll:(id)
selectAll=YES;
[self setNeedsDisplay:YES];
- (IBAction)copy:(id)
NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
[pasteBoard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil];
[pasteBoard setString:stringValue forType:NSStringPboardType];
- (void)mouseDown:(NSEvent *)theEvent
if ([theEvent clickCount]&=2) {
selectAll=YES;
[self setNeedsDisplay:YES];
- (void)keyDown:(NSEvent *)theEvent
运行实例,可以看到随着LXTextField收到系统发送的becomeFirstResponder消息,LXTextField变成responder chain中的frist responder, 这时候可以理解为IB里的哪个First Responder虚拟实例被该LXTextField取代。这时候mainMenu上哪些菜单项,例如:全选(cmd+a), 拷贝(cmd+a)等事件都会最先发给当前这个LXTextField。一旦你的LXTextField实现了NSResponder的哪些默认函数,那么该对象就会截取系统事件。当然这些事件具体如何实现还是需要你自己写代码实现。例如这里的
- (IBAction)copy:(id) 显然我手动实现了textfield的copy能力。
注意上述代码中我实现了一个空函数- (void)keyDown:(NSEvent *)theEvent 这意味着我们希望LXTextField截取键盘事件而不再传递给responder chain后续对象。当然,如果我们希望LXTextField响应特定键盘事件,而其他事件继续传给其他响应对象,我们可以编写如下代码。
- (void)keyDown:(NSEvent *)theEvent
if(condition){
[super keyDown:theEvent];
7. mem-ory management
这个也许是问得最多的问题了吧。所有这些问题往往来源于3个地方,1、不了解底层机制;2、没有吃透规则; 3、不了解常用container的Reference Counting特性,或着说没有下功夫去看对应文档。
1. 底层机制
大家是否知道从旧时代的RC到ARC机制到底意味着什么呢? 为什么ARC从开发速度,到执行速度和稳定性都要优于rc?
开发速度不言而喻,你少写很多release代码,甚至很少去操心这部分。
执行速度呢?这个还要从runtime说起,还记得我在第2点说得一句话么:“Runtime is everything between your each function call.”
RC是一个古老的内存管理哲学: 谁分配谁释放。 通过counting来确定一个资源有几个使用者。道理很简单,但是往往简单的东西人却会犯错。从来没有一个程序员可以充满信心的说,我写得代码从来没有过内存泄露。这样来看,我们就更需要让程序可以自己处理这个管理机制,这就需要把这个机制放到runtime里。
所以RC-&ARC就是把内存管理部分从普通开发者的函数中移到了函数外的runtime中。因为runtime的开发原型简单,逻辑层次更高,所以做这个开发和管理出错的概率更小。实际上编译器开发人员对这部分经过无数次测试,所以可以说用arc几乎不会出错。另外由于编译的额外优化,使得这个部分比程序员自己写得代码要快速很多。而且对于一些通用的开发模式,例如autorelease对象,arc有更优秀的算法保证autoreleasepool里的对象更少。
首先说一下rc是什么,r-Reference参照,引用 c-counting计数, rc就是引用计数。俗话说就是记录使用者的数量。 例如现在我有一个房间空着,大家可以进去随意使用,但是你进门前,需要给门口的计数牌子+1, 出门时候-1。 这时候这个门口的牌子就是该房间里的人数。一但这个牌子变为0我就可以把房间关闭。
这个规则可以让NSObject决定是不是要释放内存。当一个对象alloc时候,系统分配其一块内存并且object自动计数retainCount=1 这时候每当[object retain]一次retainCount+1(这里虽然简写也是rc不过是巧合或者当时开发人员故意选的retain这个词吧)每次[object release]时候retainCount-1 当retainCount==0时候object就真正把这快内存还给系统。
3. 常用container的Reference Counting特性
这个规则很简单把。但是这块确实让新手最头疼的地方。 问题出在,新手总想去验证rc规则,又总是发现和自己的期望不符合。  
无数次看到有人写下如下句子 复制代码
NSLog(@&%d&,[object retainCount]);
while([object retainCount]&0){
[object release];
当然了,我也做过类似的动作,那种希望一切尽在掌握中的心态。但是你会看到其他人告诉这么做完全没有意义。rc does not work this way. 也许这样的暴力释放会起作用,但是retainCount并不是用来做这个的。每个数字意味着有其它对象引用该资源,这样的暴力释放很容易导致程序崩溃。这个数字也许并不是你心目中的哪个。因为你很难跟踪到底哪些对象引用的该资源。你用代码建立的资源不光只有你的代码才会用到,你调用的各种Framework,Framework调用的Framework,都有可能改变这个资源的retainCount.
所以去验证rc规则不是明智之举。
你能做的就是理解规则,使用规则,读文档了解container的引用特性。或者干脆移到arc上面,让runtime环境处理这些问题。
我有一个NSMutableArray里面保存了1000个NSString对象,我在release的时候需要循环释放1000个string么?还是只需要release NSMutableArray。
就像上面提到的,如果你了解container的引用特性,这个问题自然就解决了。“NSMutableArray在添加、插入objects时会做retain操作。” 通过这一句话就分析出,用户不否需要帮助NSMutableArray释放1000个string。回忆上面提到的管理哲学,“谁分配谁释放” 编写NSMutableArray的程序员非常熟悉这个规则,NSMutableArray内部retain了,NSMutableArray自然要负责release。但是NSMutableArray才不会管你在外面什么地方引用了这1000个string,它只管理好内部的rc就够了。所以如果你在NSMutableArray外面对1000个string
retain了,你自然需要release。相应的,你作为创建这个NSMutableArray的程序员,你只管release这个NSMutableArray就可以了。
最后说一下不用arc的情况。目前情况来看,有不少第三方的库并未支持arc,所以如果你的旧项目使用了这些库,请检查是否作者发布了新版本,或者你需要自己修正支持arc。
8. class heritage and category
在这节里说明2个比较重要的问题,第一是subclass和category的区别。第二是新手最容易忽略的学习步骤。
Objective-C的Object-oriented programming特性提供subclass和category这2个比较非常重要的部分。subclass应该反复被各种编程书籍介绍过。它是oop继承特性的关键语法,它给类添加了延续并且多样化自己的方法。可以说没有继承就没有oop这玩意。而category相对于subclass就不那么出名了。其实category思想出世于smalltalk,所以它不能算是一个新生事物。
先说一下这2个特性最主要的区别。简单可以这么理解,subclass体现了类的上下级关系,而category是类间的平级关系。
如上图所示,左侧是subclass,可以看到class, subclass1, subclass2是递进关系。同时下面的子类完全继承父类的方法,并且可以覆盖父类的方法。subclass2拥有function1,function2,function3三个函数方法。function1的执行代码来自subclass1, function2的执行代码来自于subclass2。
右侧是category。可以看到,无论如何扩展类的category,最终就只有一个类class。category可以说是类的不同方法的小集合,它把一个类的方法划分成不同的区块。请注意观察,每个category块内的方法名称都没有重复的。这正是category的重要要求。
经过上面简单解释了解了这2点的基本区别,现在深入说一下category。
在Objective-c语言设计之初一个主要的哲学观点就是尽量让一个程序员维护庞大的代码集。(对于庞大的项目‘原则’和‘协议’是非常重要的东西。甚至编写良好的文件名都是非常重要的开发技巧)根据结构化程序设计的经验出发,把一个大块代码划分成一些小块的代码更便于程序员管理。于是objc借用了smalltalk的categories概念。允许程序员把一系列功能相近的方法组织到一个单独的文件内,使得这些代码更容易识别。
更进一步的,和c,c++这种静态语言相比。objc把class categories功能集成到了run-time里面。因此,objc的categories允许程序员为已经存在的类添加新的方法而不需要重新编译旧的类。一旦一个category加入,它可以访问该类所有方法和实例变量,包括私有变量。
category不仅可以为原有class添加方法,而且如果category方法与类内某个方法具有同样的method signature,那么category里的方法将会替换类的原有方法。这是category的替换特性。利用这个特性,category还可以用来修复一些bugs。例如已经发布的Framework出现漏洞,如果不便于重新发布新版本,可以使用category替换特性修复漏洞。另外,由于category有run-time级别的集成度,所以使得cocoa程序安全性有所下降。许多黑客就是利用这个特性(和posting技术2)劫持函数、破解软件,或者为软件增加新功能。一个很典型的例子就是,我发布的QQ表情管理器。
值得注意的一点是,由于一个类的categories之间是平级关系。所以如果不同categories拥有相同的方法,这个调用结果是未知的。所以:
Category methods should not override existing methods (class or instance).
Two different categories implementing the same method results in undefined behavior
Objc中Categories有其局限的部分,就是你不能为原有的class添加变量,只能添加方法。当然方法里可以添加局部变量。在这个局限基础上就有其它语言做了进一步改进,例如TOM语言就为Categories增加了添加类变量的能力。
总上所属,如果你开发时候遇到无论如何都需要为类添加变量的情况,最好的选择就是subclass。相反如果你只希望增加一些函数簇。Categories是最好的选择。
并且我个人给大家的建议是,每个Cocoa程序员都应该收集整理自己的一套NS类函数的Categories扩展库。这对你今后程序开发效率和掌控情况都有很大提高。
9. Design pattern
10. thinking before asking
其实剩下这个有好几点要说,但综合一下把。思路有些相似
例如刚看到这个问题:
现在有A *a;A*b
[NSMutableArray addObject : a];
[NSMutableArray replaceObjectAtIndex:0 withObject:b]
执行完这两个之后,拿可变数组里面的0 的位置 就是b元素了,那这个时候a到哪里去了??是否还占用着内存,如果占用内存的话,又如何去释放??
It's kind of silly. 我并不是想讽刺问问题的朋友。其实如果你真的了解了上面这些知识点,就不会再问这种问题的。 为什么不多思考一层呢,在问这个问题之前想想,到底为什么会问出这个问题? ”如果让你给NSMutableArray实现一个replaceObjectAtIndex函数你会怎么写?“ 难道连个[obj release]都考虑不到么?然后根据reference counting,它到底释放了没不言自明了把。
其实这种问题论坛里很多的。不妨在迷惑的时候,先问问自己为什么会迷惑。
(1)这里其实很有意思,为何我用“更高层次思考”,而不是“更底层次”。作为一个编译器和语言开发人员,面对的问题确实更底层没错,但是他们思考的维度更高,更抽象,这样子。一个不算恰当的比方就好像一个三维世界的人处理二维世界的一条线的问题。
(2)Posting技术在10.5以后deprecated,并且64bit run-time也不再支持
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:264802次
积分:2947
积分:2947
排名:第8948名
原创:36篇
转载:85篇
评论:13条
(2)(1)(2)(3)(1)(5)(1)(47)(57)(2)

参考资料

 

随机推荐