我这配置能玩dayz独立版配置吗

iOS程序员一枚,说下自己,我现在用的是的air,运行Xcode还是有些吃力的,…
&img src=&/v2-59cc67d745ccfa992b5572_b.png& data-rawwidth=&0& data-rawheight=&0& class=&content_image& width=&0&&&h1&说起配色,真是令人烦恼。&/h1&&br&&p&看了不少的配色书籍,磕磕绊绊弄懂了色相环、补色、对比色等晦涩的专有名词,却依旧对配色一筹莫展。没有好的配色,就没有精致的PPT,也没有出众的设计。&/p&&p&为此,我很想与你分享这4个关于配色的网站,希望能让我们的作品也有着设计师般专业的色彩设计。&/p&&blockquote&&p&&b&1、中国色&/b&&/p&&p&&b&&a href=&/?target=http%3A//& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&中国色 - 中国传统颜色&i class=&icon-external&&&/i&&/a&&/b&&/p&&/blockquote&&img src=&/v2-8c02d9ca33ed975ef07efef1_b.png& data-rawheight=&254& data-rawwidth=&546& class=&origin_image zh-lightbox-thumb& width=&546& data-original=&/v2-8c02d9ca33ed975ef07efef1_r.png&&&br&中国色网站首页&br&&p&这个网站收藏了最全的&b&中国色&/b&,以色卡的形式呈现,中英文互译更是方便我们辨识。&/p&&p&但这些绝不仅仅是我向你们推荐这个网站的全部理由,这个网站最棒之处在于当你点击某个颜色的色卡时,整个网页都会渲染成你点的那个颜色,并以&b&CMYK&/b&和&b&RGB&/b&两种模式提供精确的颜色数值。&/p&&p&做设计的人会发现,某些颜色在色卡上看来很棒,但是大面积使用过后却可能并不适合,所以这个网站整页铺叠的方式便可在一定程度上避免这种弊端,十分方便。&/p&&br&&img src=&/v2-cb323d4bb21bc_b.png& data-rawheight=&252& data-rawwidth=&545& class=&origin_image zh-lightbox-thumb& width=&545& data-original=&/v2-cb323d4bb21bc_r.png&&&br&紫薇花色&br&&blockquote&&p&&b&2、uiGradients &br&&/b&&/p&&p&&b&&a href=&/?target=http%3A///%23ServQuick& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&uiGradients - Beautiful colored gradients&i class=&icon-external&&&/i&&/a&&/b&&br&&/p&&/blockquote&&img src=&/v2-9265f5bdf73e4c4cb6d5d2_b.png& data-rawheight=&250& data-rawwidth=&554& class=&origin_image zh-lightbox-thumb& width=&554& data-original=&/v2-9265f5bdf73e4c4cb6d5d2_r.png&&&br&uiGradients网站首页&br&&p&uiGradients是专业的&b&渐变色配色&/b&网站,当我们点击左下角的See All Gradients按钮时,便可以看到众多的渐变色配色方案,商务风、甜美风等风格应有尽有,就像下图这样。&/p&&br&&img src=&/v2-59cc67d745ccfa992b5572_b.png& data-rawheight=&214& data-rawwidth=&554& class=&origin_image zh-lightbox-thumb& width=&554& data-original=&/v2-59cc67d745ccfa992b5572_r.png&&&br&各种各样的配色方案&br&&p&当你从众多的配色方案中选择出了心仪的那一个,不妨点进去,便可以看到具体的配色,就像下面这样。&/p&&br&&img src=&/v2-73ca9f26f1a458dd026b6d0af1f033fe_b.png& data-rawheight=&254& data-rawwidth=&554& class=&origin_image zh-lightbox-thumb& width=&554& data-original=&/v2-73ca9f26f1a458dd026b6d0af1f033fe_r.png&&&br&名为“sweet morning”的配色&br&&p&这个网站的便捷之处还在于点击色号旁边的小按钮便可以&b&复制&/b&,&b&右击还可以将图片另存为&/b&,免费下载哦,真是懒人的福利啊!&/p&&p&另外该网站还可以将配色图片&b&分享到脸书和推特&/b&上哟~&/p&&p&但是这个网站还有一个小小的不便利之处,就是没有将渐变色方案进行分类,也没有提供相应的搜索,有的时候得要找好久才能找到满意的配色方案。&/p&&blockquote&&p&&b&3、Color Hunt &br&&/b&&/p&&p&&b&&a href=&/?target=http%3A//www.colorhunt.co/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Color Hunt&i class=&icon-external&&&/i&&/a&&/b&&br&&/p&&/blockquote&&img src=&/v2-d7ce55007dbe_b.png& data-rawheight=&245& data-rawwidth=&554& class=&origin_image zh-lightbox-thumb& width=&554& data-original=&/v2-d7ce55007dbe_r.png&&&br&Color Hunt网站首页&br&&p&这个网站以时间为序,&b&每天都会更新一个配色方案&/b&,我们可以直接用哦。&/p&&p&当你点击页面上方正中间的大舌头脸图案,便可以刷新页面回到主页。同时,你也可以点击页面左上角的New,Hot,Popular和 Random按钮,查看一些热门的配色方案。&/p&&p&当你看中某个配色方案时,将鼠标置于颜色之上,便会出现该种颜色的网页代码,可以直接复制。同时,你也可以为你喜欢的配色方案点赞哦~&/p&&p&这个网站的不足之处在于更新有点慢,没有将配色方案按照主题进行分类,不方便我们在需要时检索。&/p&&blockquote&&p&&b&4、配色网&br&&/b&&/p&&p&&b&&a href=&/?target=http%3A//www.peise.net/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&配色网-致力色彩搭配方案的交流与学习&i class=&icon-external&&&/i&&/a&&/b&&br&&/p&&/blockquote&&img src=&/v2-061bdea5a46bfd8dfb34_b.png& data-rawheight=&243& data-rawwidth=&543& class=&origin_image zh-lightbox-thumb& width=&543& data-original=&/v2-061bdea5a46bfd8dfb34_r.png&&&br&配色网网站首页&br&&p&配色网的便捷之处在于提供了&b&色彩分类&/b&和&b&常用标签&/b&(在网页首页的右边),方便我们根据自己的目标进行检索。同时,这个网站相比前三个多了许多色彩相关版块,大家可以看到网页右上角有&b&下载、学习、色彩、配色&/b&等版块。&/p&&br&&img src=&/v2-168835acb859abcec627761_b.png& data-rawheight=&254& data-rawwidth=&543& class=&origin_image zh-lightbox-thumb& width=&543& data-original=&/v2-168835acb859abcec627761_r.png&&&br&下载版块&br&&p&下载版块分享的是一些&b&色环、色谱以及相关实用软件&/b&的下载,还贴心地在下方附上了&b&下载地址&/b&。&/p&&br&&img src=&/v2-fffadb97218_b.png& data-rawheight=&252& data-rawwidth=&545& class=&origin_image zh-lightbox-thumb& width=&545& data-original=&/v2-fffadb97218_r.png&&&br&学习版块&br&&p&学习板块提供了一些关于&b&色彩、配色&/b&的知识,还有一些&b&色彩心理学、色彩风水学&/b&的知识,方便人们在寻找配色方案的同时get一些色彩知识。&/p&&br&&img src=&/v2-6adb313e32d976eb93a1c1_b.png& data-rawheight=&253& data-rawwidth=&545& class=&origin_image zh-lightbox-thumb& width=&545& data-original=&/v2-6adb313e32d976eb93a1c1_r.png&&&br&色彩版块&br&&p&色彩版块着重介绍一些色彩,大家可以看着缤纷的&b&色条&/b&、优美的&b&名字&/b&学习一些基础的色彩知识。&/p&&br&&img src=&/v2-403ba818a6cb201b2be6bae_b.png& data-rawheight=&251& data-rawwidth=&545& class=&origin_image zh-lightbox-thumb& width=&545& data-original=&/v2-403ba818a6cb201b2be6bae_r.png&&&br&搭配版块&br&&p&最最实用的莫过于搭配版块了,大家可以看到众多&b&配色方案&/b&,以及他们各自潮流的名字。&/p&&p&除了一些&b&常用的检索标签&/b&,网页右下角还分享了&b&本周流行搭配排行&/b&,时时跟紧潮流的步伐~&/p&&p&当我们选取到了合适的配色方案后,点进去,网页提供了&b&HEX&/b&、&b&RGB&/b&和&b&CMYK&/b&三种颜色模式,非常方便。&/p&&p&相信有了这四个配色网站,我们的PPT、海报等作品将彻底告别low的配色。也许我们不是专业的设计师,但我们依旧可以拥有专业潮流的配色方案~&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&我是刘小小,求包养哈~
&/code&&/pre&&/div&
说起配色,真是令人烦恼。 看了不少的配色书籍,磕磕绊绊弄懂了色相环、补色、对比色等晦涩的专有名词,却依旧对配色一筹莫展。没有好的配色,就没有精致的PPT,也没有出众的设计。为此,我很想与你分享这4个关于配色的网站,希望能让我们的作品也有着设计…
&b&谁用谁知道、快得飞起来,后悔怎么没早装、为什么不是每台都装、没装的怎么这么笨。。。。&/b&&br&&br&对了,不要犹豫,现在就买!我来的绝对是干货,STEP BY STEP&br&&br&&b&硬件篇:&/b&&br&1、上电商,根据自己的经济条件买大厂商SSD产品&b&(小白的话,千万不要到电脑城买。。。。)&/b&&br&2、弄一根SATA线(必选,一般机箱里只有一根)&br&3、弄一个硬盘托架和四个螺丝(买SSD的时候,注意买有托架奉送的,没有的话自己有螺丝也可以)&br&4、打开机箱,可以直接用2个螺丝把SSD固定在全尺寸硬盘托架的一边,如果有小托架就可以四个螺丝两面固定。&br&&br&&b&软件篇:&/b&&br&1、网上下载一个EASEUS分区大师家庭免费版,装好&br&2、使用菜单里的SSD迁移功能,将C盘移到SSD(不需要格式化SSD)&br&3、启动电脑,把第一启动设备设为SSD&br&4、享受高速。&br&&br&&br&&b&,喜欢的点赞,嘿嘿。&/b&
谁用谁知道、快得飞起来,后悔怎么没早装、为什么不是每台都装、没装的怎么这么笨。。。。 对了,不要犹豫,现在就买!我来的绝对是干货,STEP BY STEP 硬件篇: 1、上电商,根据自己的经济条件买大厂商SSD产品(小白的话,千万不要到电脑城买。。。。) 2、…
&b&谁用谁知道、快得飞起来,后悔怎么没早装、为什么不是每台都装、没装的怎么这么笨。。。。&/b&&br&&br&对了,不要犹豫,现在就买!我来的绝对是干货,STEP BY STEP&br&&br&&b&硬件篇:&/b&&br&1、上电商,根据自己的经济条件买大厂商SSD产品&b&(小白的话,千万不要到电脑城买。。。。)&/b&&br&2、弄一根SATA线(必选,一般机箱里只有一根)&br&3、弄一个硬盘托架和四个螺丝(买SSD的时候,注意买有托架奉送的,没有的话自己有螺丝也可以)&br&4、打开机箱,可以直接用2个螺丝把SSD固定在全尺寸硬盘托架的一边,如果有小托架就可以四个螺丝两面固定。&br&&br&&b&软件篇:&/b&&br&1、网上下载一个EASEUS分区大师家庭免费版,装好&br&2、使用菜单里的SSD迁移功能,将C盘移到SSD(不需要格式化SSD)&br&3、启动电脑,把第一启动设备设为SSD&br&4、享受高速。&br&&br&&br&&b&,喜欢的点赞,嘿嘿。&/b&
谁用谁知道、快得飞起来,后悔怎么没早装、为什么不是每台都装、没装的怎么这么笨。。。。 对了,不要犹豫,现在就买!我来的绝对是干货,STEP BY STEP 硬件篇: 1、上电商,根据自己的经济条件买大厂商SSD产品(小白的话,千万不要到电脑城买。。。。) 2、…
&img src=&/v2-fbe860c3fffcf3e83356e17_b.jpg& data-rawwidth=&0& data-rawheight=&0& class=&content_image& width=&0&&&p&(知乎尺度太小,上一篇被河蟹,修改了下)&/p&&p&人的一生有几个关键点,分别是出生、求学、就业和婚姻。&/p&&p&前面的每一个点又会影响到后面的所有点,并且还相互交织影响。(出生就在很大程度上影响求学、就业和婚姻,求学又在很大程度上决定就业及婚姻,就业也在很大程度上影响婚姻)&br&&/p&&img src=&/v2-8556ebde3c6d9edd0002dd_b.png& data-rawwidth=&374& data-rawheight=&170& class=&content_image& width=&374&&&p&但是这四个点中,出生是我们每个人都无法选择的。&/p&&p&从这个角度来看,命运还是有其道理。命是定数,运乃变数,不能改变的过去造就了你的命,无法预测的未来影响了你的运。&/p&&p&命为人一生之所归,命有天数、有定律,出生于帝王之家或脱胎于贫困之地,自会有截然不同之归宿;运是人一生之历程,运有起伏、有顺逆,倘若某些高官不东窗事发,其后代之境遇定不同于今时今日。&/p&&p&一个人出生的地方、家庭及其观念和文化无形中渗透进人的意识里,使得你成为了一个独特的你,这就是你的命;后天的环境、教育的浸润与同伴的影响既可能带来转机,也可能加深禁锢,并影响到你的一生,这些都是不能完全预测和把控的运。&/p&&p&命是与生俱来的,运却是变动不居的。虽说人不能完全预测和把控外在世界,却可以在很大程度上掌握自己,并进而影响外在环境和事件。&/p&&p&一个人无法改变自己的过去,也无法准确预测自己的将来,唯一可以把握的是我们的现在。&/p&&p&我最喜欢的一段话是:&/p&&p&愿上帝赐予我平静 ,能接纳我无法改变的事;&br&God grant me the serenity ,to accept the things I &br&&br&愿上帝赐予我勇气,能改变我可以改变的事;&br&courage to change the things I &br&&br&并赐予我智慧,让我能分辨这两者的不同。&br&and wisdom to know the difference.&br&&/p&&p&然而实际上,并没有上帝,或者说,我们都是自己的上帝。&/p&&p&倘若我们能真切地意识到这些问题,能够对自己和所处的环境进行深入地分析,并在此基础上形成自己的能动性,自动自发地努力提升自己和改变外在环境,当能逐渐转换命运,在一定程度上实现我命由我不由天。&/p&&img src=&/v2-a78f78b2b14ee6ab65be_b.jpg& data-rawwidth=&351& data-rawheight=&220& class=&content_image& width=&351&&&p&然而,除了努力外,抉择同样也非常关键!甚至一旦抉择错误,怎么努力都没用,或者至少会消耗你的很多精力,浪费你的很多时间。(其实明智的抉择本身就是需要努力的)&/p&&p&在我们的一生中,我们要做出太多的抉择,而所有的抉择中影响我们最大的两个:一个是选对老板,一个是选对老婆(老公)。&/p&&p&日出而作,日落而息----白天你要和老板共事,晚上你要和老婆共处。&/p&&p&01 选对老婆(老公)&/p&&img src=&/v2-fbe860c3fffcf3e83356e17_b.jpg& data-rawwidth=&1024& data-rawheight=&683& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&/v2-fbe860c3fffcf3e83356e17_r.jpg&&&p&老婆的重要性不仅在于她和你相处的时间长,更在于她会在很大程度上影响你的生活质量。&/p&&p&一个男人的最高品味是他选择的女人,浓妖不及淡久,越艳丽的东西越容易受到关注,也就越容易受到伤害,而平常的不起眼的东西越能存在的长久。&/p&&p&前段时间接触到一个地产公司HR的区域负责人,年近四旬,按理他应该属于标准的中产,收入至少也是好大几十万一年,然而他的近况却让人大跌眼镜。&/p&&p&其中一个重要原因在于他和老婆离婚了,这还不算,还是净身出户。&/p&&p&按他的描述,他老婆大概类似于无理取闹的类型,他工作繁忙很晚才回家的时候,老婆还经常大吵大闹,有些时候生气了就威胁从楼上往下跳,而且会真的往下跳,所以他从来不敢怎样。&/p&&p&另外,吵架的时候他老婆会不让他上班,甚至跑去公司吵闹。&/p&&p&最后没办法,他提出离婚,老婆不答应,表示除非他净身出户。完了之后,他真的净身出户了,车和房都不要了,小孩归他老婆,而且他还每个月承担不菲的抚养费。&/p&&p&所以说,娶一个好女人,她能够支持你、鼓励你,并在最困难的时候陪伴你,那简直是生命里的一道光,照亮前进的方向,俩人举案齐眉、相濡以沫,快哉!幸哉!&/p&&p&反之,悍妻诟谇,真不若耳聋也!(有凶悍的妻子辱骂斥责着,真不如耳聋了好)只有家庭和睦,心态健康的人,才具备闲适的条件。有了这个条件,生活才能幸福,事业也才能更容易取得成功。&/p&&p&选老公的重要性就更不用说了,女孩子和她们老妈比我们都清楚,无需赘言。不过她们更多地是基于经济的角度考虑,双鸟在林不如一鸟在手,看得见的最重要,别去谈什么虚无缥缈的潜力啊慧眼啊什么的。&/p&&p&这个好理解,也没啥可批判的,各人价值理念不同,只要不妨害社会和他人就无所谓。&/p&&p&02 找对老板&/p&&img src=&/v2-de601e41c0ac634c84e9c_b.jpg& data-rawwidth=&550& data-rawheight=&483& class=&origin_image zh-lightbox-thumb& width=&550& data-original=&/v2-de601e41c0ac634c84e9c_r.jpg&&&p&至于选对老板,其实更多的是指职业、工作和平台。(甚至你也可以自己当老板,打造属于自己的平台)&/p&&p&不同行业和职业、工作与平台,决定了你的薪酬待遇、发展空间以及生活质量和生活方式。&/p&&p&一图胜千言,看图的感受最直观。(下图左右对比)&/p&&p&&img src=&/v2-3aaee80ea8c_b.png& data-rawwidth=&433& data-rawheight=&170& class=&origin_image zh-lightbox-thumb& width=&433& data-original=&/v2-3aaee80ea8c_r.png&&另外,虽然我们国家在宣传中有意识地淡化阶层,但实际上,不管你愿不愿意,它一直就在那里,不远也不近,你可以忽视它,但它总是会在某个时刻让你感受到它的存在,不经意间撩拨你的神经。&/p&&p&阶层和什么有关呢?&/p&&p&有很多,比如你的家庭、教育背景、收入,等等,但最直接相关的就是----职业,其他的都是通过影响职业这一因素来影响你的阶层。&/p&&img src=&/v2-d81f47b28a339fba17a516ea84382b73_b.png& data-rawwidth=&309& data-rawheight=&268& class=&content_image& width=&309&&&p&要理解职业呢,实际上不仅仅是职业本身,而是要站在一个更大的层次来看。&br&&/p&&p&&img src=&/v2-bdd334dc503_b.png& data-rawwidth=&247& data-rawheight=&208& class=&content_image& width=&247&&最外层是行业,接下来才是职业,最里层的还有组织乃至具体的岗位。&br&&/p&&p&行业是类似企业(提供相同产品或服务)的集合,不同的行业,由于它的行业性质不一样,竞争程度以及对人的从业门槛的要求不同,不论是在工作环境上、待遇上还是发展空间上,不同行业都存在很大的差异,所以说入行一定要慎重。&/p&&p&职业是性质相近的工作的总称。举个例子,这个老师是教小学语文的,这个老师是教小学数学的,他们的工作其实都比较相近,把他们一整合起来,其实都是老师,就形成了教师这个职业。&/p&&p&组织是具体的单位,可以简单粗暴分为体制内和体制外,或者进一步划分为政府机构、事业单位、国企、民企、外企等,另外,不同类别又有三六九等的划分,不同组织类型和级别的工作特点及发展待遇和空间也有不同的。&/p&&p&岗位则涉及到你在一个组织中具体做什么,直接决定了你的工作内容和待遇。&/p&&p&以财务或会计专业为例,你可能会进入不同的行业(地产、制造、金融等)、不同的组织(国企、民企、外企),从事不同的岗位(出纳、材料会计、审计、财务主管等)。&/p&&p&在不同时间里,你的行业、组织和岗位变化轨迹,就构成了你的职业生涯。&/p&&img src=&/v2-bf311ca66cd8f6b22b759e4af42816c8_b.jpg& data-rawwidth=&348& data-rawheight=&300& class=&content_image& width=&348&&&p&生活的悲剧在于,很多时候直到我们毕业多年才会真切意识到这些问题,可是当我们意识到这些问题的时候,就已经错过了不少时机,浪费了很多机会。&/p&&p&倘若我们在毕业之前能够真切地意识到职业生涯规划的必要性和可行性,并付诸努力和行动,我们真的可以少走很多弯路。&/p&&p&03 小结&/p&&p&有时候我发现些很有趣的现象:我们很容易在小事乃至无关紧要的事情上斤斤计较、精打细算,却反而在重要的关键的事情上没有任何意识和规划。&/p&&p&比如不少女孩子,买衣服的时候绝对是精挑细选,又是花色又是材料的,又是款式又是裁剪,对着镜子照了又照、看了又看,征询店员的看法,寻求闺蜜的建议,不换个五六七八九十套是不会善罢甘休的。&/p&&p&这当然是没有问题的,然而倘若她们拿出购物逛街化妆的哪怕十分之一的时间和精力在职业发展方面,我觉得她们毕业后应该就不会有那么多的抱怨了,一会抱怨单位low、工作累,一会抱怨工作无聊工资还低,完了看看今后发展,那就更是缥缈不知所踪了。&/p&&p&因此,在对我们产生重要影响的职业抉择方面,我还是提几个建议:&br&&/p&&p&1.尽早准备:尽早做职业规划与自我分析,尽早做好面对工作的心理准备;&/p&&p&2.实践探索:多一些实践性探索,增加工作世界的体验和认识;&/p&&p&3.调整心态:调整心态,而非苛求完美或理想的工作;&/p&&p&4.开放灵活:灵活开放,动态发展,而非僵固保守。&/p&&p&同样地,找老婆(老公)也是一样,虽说婚姻最好还是要有爱情,可婚姻又不仅仅是爱情。两个年轻人谈恋爱,相互喜欢就足够,可是谈婚论嫁就不同了。&/p&&p&日子久了,柴米油盐酱醋茶,很容易把你们的激情消磨殆尽。这时候最关键的有这么几条:双方的经济实力和水平、双方的价值理念和追求、双方的性格特征与爱好。&/p&&p&倘若双方都没钱,那真是贫贱夫妻百事哀啊;倘若双方收入水平相差太远,一方太强,一方太弱,也容易出问题;倘若双方价值理念和追求不一致,又或者双方性格不搭,抑或是一方性格奇葩,矛盾也迟早还是会爆发。&/p&&p&虽然我们的一生很长,有不少试错机会,一般不至于一次决策失误就毁终身,但重大决策的失误至少会给我们的工作和生活带来很多麻烦,甚至让我们付出极大的代价,譬如宝宝。&/p&&p&现在就开始行动吧,不要等到毕业多年后才开始考虑自己的职业生涯发展,就像不要结婚多年之后才后悔娶了一个悍妇或是恶女人一样。&/p&&img src=&/v2-5fb39ec3bfdfccb390f85f_b.jpg& data-rawwidth=&482& data-rawheight=&278& class=&origin_image zh-lightbox-thumb& width=&482& data-original=&/v2-5fb39ec3bfdfccb390f85f_r.jpg&&&p&欢迎关注我的知乎专栏和微信公众号----骐骥堂&/p&
(知乎尺度太小,上一篇被河蟹,修改了下)人的一生有几个关键点,分别是出生、求学、就业和婚姻。前面的每一个点又会影响到后面的所有点,并且还相互交织影响。(出生就在很大程度上影响求学、就业和婚姻,求学又在很大程度上决定就业及婚姻,就业也在很大…
&img src=&/v2-a62d76b4d533ed2ca38ab9_b.jpg& data-rawwidth=&0& data-rawheight=&0& class=&content_image& width=&0&&&p&稍有 iOS 开发经验的人应该都是用过 CocoaPods,而对于 CI、CD 有了解的同学也都知道 Fastlane。而这两个在 iOS 开发中非常便捷的第三方库都是使用 Ruby 来编写的,这是为什么?&/p&&p&先抛开这个话题不谈,我们来看一下 CocoaPods 和 Fastlane 是如何使用的,首先是 CocoaPods,在每一个工程使用 CocoaPods 的工程中都有一个 Podfile:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&source '/CocoaPods/Specs.git'
target 'Demo' do
pod 'Mantle', '~& 1.5.1'
pod 'SDWebImage', '~& 3.7.1'
pod 'BlocksKit', '~& 2.2.5'
pod 'SSKeychain', '~& 1.2.3'
pod 'UMengAnalytics', '~& 3.1.8'
pod 'UMengFeedback', '~& 1.4.2'
pod 'Masonry', '~& 0.5.3'
pod 'AFNetworking', '~& 2.4.1'
pod 'Aspects', '~& 1.4.1'
&/code&&/pre&&/div&&p&这是一个使用 Podfile 定义依赖的一个例子,不过 Podfile 对约束的描述其实是这样的:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&source('/CocoaPods/Specs.git')
target('Demo') do
pod('Mantle', '~& 1.5.1')
&/code&&/pre&&/div&&blockquote&&p&Ruby 代码在调用方法时可以省略括号。&/p&&/blockquote&&p&Podfile 中对于约束的描述,其实都可以看作是对代码简写,上面的代码在解析时可以当做 Ruby 代码来执行。&/p&&p&Fastlane 中的代码 Fastfile 也是类似的:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&lane :beta do
increment_build_number
testflight
sh &./customScript.sh&
&/code&&/pre&&/div&&p&使用描述性的”代码“编写脚本,如果没有接触或者使用过 Ruby 的人很难相信上面的这些文本是代码的。&/p&&h2&Ruby 概述&/h2&&p&在介绍 CocoaPods 的实现之前,我们需要对 Ruby 的一些特性有一个简单的了解,在向身边的朋友“传教”的时候,我往往都会用优雅这个词来形容这门语言(手动微笑)。&/p&&p&除了优雅之外,Ruby 的语法具有强大的表现力,并且其使用非常灵活,能快速实现我们的需求,这里简单介绍一下 Ruby 中的一些特性。&/p&&h3&一切皆对象&/h3&&p&在许多语言,比如 Java 中,数字与其他的基本类型都不是对象,而在 Ruby 中所有的元素,包括基本类型都是对象,同时也不存在运算符的概念,所谓的 1 + 1,其实只是 1.+(1) 的语法糖而已。&/p&&p&得益于一切皆对象的概念,在 Ruby 中,你可以向任意的对象发送 methods 消息,在运行时自省,所以笔者在每次忘记方法时,都会直接用 methods 来“查文档”:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&2.3.1 :003 & 1.methods
=& [:%, :&, :*, :+, :-, :/, :&, :&, :^, :|, :~, :-@, :**, :&=&, :&&, :&&, :&=, :&=, :==, :===, :[], :inspect, :size, :succ, :to_s, :to_f, :div, :divmod, :fdiv, :modulo, :abs, :magnitude, :zero?, :odd?, :even?, :bit_length, :to_int, :to_i, :next, :upto, :chr, :ord, :integer?, :floor, :ceil, :round, :truncate, :downto, :times, :pred, :to_r, :numerator, :denominator, :rationalize, :gcd, :lcm, :gcdlcm, :+@, :eql?, :singleton_method_added, :coerce, :i, :remainder, :real?, :nonzero?, :step, :positive?, :negative?, :quo, :arg, :rectangular, :rect, :polar, :real, :imaginary, :imag, :abs2, :angle, :phase, :conjugate, :conj, :to_c, :between?, :instance_of?, :public_send, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :private_methods, :kind_of?, :instance_variables, :tap, :is_a?, :extend, :define_singleton_method, :to_enum, :enum_for, :=~, :!~, :respond_to?, :freeze, :display, :send, :object_id, :method, :public_method, :singleton_method, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :trust, :untrusted?, :methods, :protected_methods, :frozen?, :public_methods, :singleton_methods, :!, :!=, :__send__, :equal?, :instance_eval, :instance_exec, :__id__]
&/code&&/pre&&/div&&p&比如在这里向对象 1 调用 methods 就会返回它能响应的所有方法。&/p&&p&一切皆对象不仅减少了语言中类型的不一致,消灭了基本数据类型与对象之间的边界;这一概念同时也简化了语言中的组成元素,这样 Ruby 中只有对象和方法,这两个概念,这也降低了我们理解这门语言的复杂度:&/p&&ul&&li&使用对象存储状态&/li&&li&对象之间通过方法通信&/li&&/ul&&h3&block&/h3&&p&Ruby 对函数式编程范式的支持是通过 block,这里的 block 和 Objective-C 中的 block 有些不同。&/p&&p&首先 Ruby 中的 block 也是一种对象,所有的 Block 都是 Proc 类的实例,也就是所有的 block 都是 first-class 的,可以作为参数传递,返回。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def twice(&proc)
2.times { proc.call() } if proc
2.times { yield } if block_given?
&/code&&/pre&&/div&&blockquote&&p&yield 会调用外部传入的 block,block_given? 用于判断当前方法是否传入了 block。&/p&&/blockquote&&p&在这个方法调用时,是这样的:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&twice do
puts &Hello&
&/code&&/pre&&/div&&h3&eval&/h3&&p&最后一个需要介绍的特性就是 eval 了,早在几十年前的 Lisp 语言就有了 eval 这个方法,这个方法会将字符串当做代码来执行,也就是说 eval 模糊了代码与数据之间的边界。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&& eval &1 + 2 * 3&
&/code&&/pre&&/div&&p&有了 eval 方法,我们就获得了更加强大的动态能力,在运行时,使用字符串来改变控制流程,执行代码;而不需要去手动解析输入、生成语法树。&/p&&h3&手动解析 Podfile&/h3&&p&在我们对 Ruby 这门语言有了一个简单的了解之后,就可以开始写一个简易的解析 Podfile 的脚本了。&/p&&p&在这里,我们以一个非常简单的 Podfile 为例,使用 Ruby 脚本解析 Podfile 中指定的依赖:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&source 'http://source.git'
platform :ios, '8.0'
target 'Demo' do
pod 'AFNetworking'
pod 'SDWebImage'
pod 'Masonry'
pod &Typeset&
pod 'BlocksKit'
pod 'Mantle'
pod 'IQKeyboardManager'
pod 'IQDropDownTextField'
&/code&&/pre&&/div&&p&因为这里的 source、platform、target 以及 pod 都是方法,所以在这里我们需要构建一个包含上述方法的上下文:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# eval_pod.rb
$hash_value = {}
def source(url)
def target(target)
def platform(platform, version)
def pod(pod)
&/code&&/pre&&/div&&p&使用一个全局变量 hash_value 存储 Podfile 中指定的依赖,并且构建了一个 Podfile 解析脚本的骨架;我们先不去完善这些方法的实现细节,先尝试一下读取 Podfile 中的内容并执行会不会有什么问题。&/p&&p&在 eval_pod.rb 文件的最下面加入这几行代码:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&content = File.read './Podfile'
eval content
p $hash_value
&/code&&/pre&&/div&&p&这里读取了 Podfile 文件中的内容,并把其中的内容当做字符串执行,最后打印 hash_value 的值。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&$ ruby eval_pod.rb
&/code&&/pre&&/div&&p&运行这段 Ruby 代码虽然并没有什么输出,但是并没有报出任何的错误,接下来我们就可以完善这些方法了:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def source(url)
$hash_value['source'] = url
def target(target)
targets = $hash_value['targets']
targets = [] if targets == nil
targets && target
$hash_value['targets'] = targets
yield if block_given?
def platform(platform, version)
def pod(pod)
pods = $hash_value['pods']
pods = [] if pods == nil
pods && pod
$hash_value['pods'] = pods
&/code&&/pre&&/div&&p&在添加了这些方法的实现之后,再次运行脚本就会得到 Podfile 中的依赖信息了,不过这里的实现非常简单的,很多情况都没有处理:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&$ ruby eval_pod.rb
{&source&=&&http://source.git&, &targets&=&[&Demo&], &pods&=&[&AFNetworking&, &SDWebImage&, &Masonry&, &Typeset&, &BlocksKit&, &Mantle&, &IQKeyboardManager&, &IQDropDownTextField&]}
&/code&&/pre&&/div&&p&CocoaPods 中对于 Podfile 的解析与这里的实现其实差不多,接下来就进入了 CocoaPods 的实现部分了。&/p&&h2&CocoaPods 的实现&/h2&&p&在上面简单介绍了 Ruby 的一些语法以及如何解析 Podfile 之后,我们开始深入了解一下 CocoaPods 是如何管理 iOS 项目的依赖,也就是 pod install 到底做了些什么。&/p&&h3&Pod install 的过程&/h3&&p&pod install 这个命令到底做了什么?首先,在 CocoaPods 中,所有的命令都会由 Command 类派发到将对应的类,而真正执行 pod install 的类就是 Install:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module Pod
class Command
class Install & Command
verify_podfile_exists!
installer = installer_for_config
installer.repo_update = repo_update?(:default =& false)
installer.update = false
installer.install!
&/code&&/pre&&/div&&p&这里面会从配置类的实例 config 中获取一个 Installer 的实例,然后执行 install! 方法,这里的 installer 有一个 update 属性,而这也就是 pod install 和 update 之间最大的区别,&strong&其中后者会无视已有的 Podfile.lock 文件,重新对依赖进行分析&/strong&:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module Pod
class Command
class Update & Command
installer = installer_for_config
installer.repo_update = repo_update?(:default =& true)
installer.update = true
installer.install!
&/code&&/pre&&/div&&h3&Podfile 的解析&/h3&&p&Podfile 中依赖的解析其实是与我们在手动解析 Podfile 章节所介绍的差不多,整个过程主要都是由 &strong&CocoaPods-Core&/strong& 这个模块来完成的,而这个过程早在 installer_for_config 中就已经开始了:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def installer_for_config
Installer.new(config.sandbox, config.podfile, config.lockfile)
&/code&&/pre&&/div&&p&这个方法会从 config.podfile 中取出一个 Podfile 类的实例:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def podfile
@podfile ||= Podfile.from_file(podfile_path) if podfile_path
&/code&&/pre&&/div&&p&类方法 Podfile.from_file 就定义在 CocoaPods-Core 这个库中,用于分析 Podfile 中定义的依赖,这个方法会根据 Podfile 不同的类型选择不同的调用路径:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&Podfile.from_file
`-- Podfile.from_ruby
|-- File.open
&/code&&/pre&&/div&&p&from_ruby 类方法就会像我们在前面做的解析 Podfile 的方法一样,从文件中读取数据,然后使用 eval 直接将文件中的内容当做 Ruby 代码来执行。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def self.from_ruby(path, contents = nil)
contents ||= File.open(path, 'r:utf-8', &:read)
podfile = Podfile.new(path) do
eval(contents, nil, path.to_s)
rescue Exception =& e
message = &Invalid `#{path.basename}` file: #{e.message}&
raise DSLError.new(message, path, e, contents)
&/code&&/pre&&/div&&p&在 Podfile 这个类的顶部,我们使用 Ruby 的 Mixin 的语法来混入 Podfile 中代码执行所需要的上下文:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&include Pod::Podfile::DSL
&/code&&/pre&&/div&&p&Podfile 中的所有你见到的方法都是定义在 DSL 这个模块下面的:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module Pod
class Podfile
module DSL
def pod(name = nil, *requirements) end
def target(name, options = nil) end
def platform(name, target = nil) end
def inhibit_all_warnings! end
def use_frameworks!(flag = true) end
def source(source) end
&/code&&/pre&&/div&&p&这里定义了很多 Podfile 中使用的方法,当使用 eval 执行文件中的代码时,就会执行这个模块里的方法,在这里简单看一下其中几个方法的实现,比如说 source 方法:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def source(source)
hash_sources = get_hash_value('sources') || []
hash_sources && source
set_hash_value('sources', hash_sources.uniq)
&/code&&/pre&&/div&&p&该方法会将新的 source 加入已有的源数组中,然后更新原有的 sources 对应的值。&/p&&p&稍微复杂一些的是 target 方法:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def target(name, options = nil)
if options
raise Informative, &Unsupported options `#{options}` for & \
&target `#{name}`.&
parent = current_target_definition
definition = TargetDefinition.new(name, parent)
self.current_target_definition = definition
yield if block_given?
self.current_target_definition = parent
&/code&&/pre&&/div&&p&这个方法会创建一个 TargetDefinition 类的实例,然后将当前环境系的 target_definition 设置成这个刚刚创建的实例。这样,之后使用 pod 定义的依赖都会填充到当前的 TargetDefinition 中:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def pod(name = nil, *requirements)
unless name
raise StandardError, 'A dependency requires a name.'
current_target_definition.store_pod(name, *requirements)
&/code&&/pre&&/div&&p&当 pod 方法被调用时,会执行 store_pod 将依赖存储到当前 target 中的 dependencies 数组中:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def store_pod(name, *requirements)
return if parse_subspecs(name, requirements)
parse_inhibit_warnings(name, requirements)
parse_configuration_whitelist(name, requirements)
if requirements && !requirements.empty?
pod = { name =& requirements }
pod = name
get_hash_value('dependencies', []) && pod
&/code&&/pre&&/div&&p&总结一下,CocoaPods 对 Podfile 的解析与我们在前面做的手动解析 Podfile 的原理差不多,构建一个包含一些方法的上下文,然后直接执行 eval 方法将文件的内容当做代码来执行,这样只要 Podfile 中的数据是符合规范的,那么解析 Podfile 就是非常简单容易的。&/p&&h3&***依赖的过程&/h3&&p&Podfile 被解析后的内容会被转化成一个 Podfile 类的实例,而 Installer 的实例方法 install! 就会使用这些信息***当前工程的依赖,而整个***依赖的过程大约有四个部分:&/p&&ul&&li&解析 Podfile 中的依赖&/li&&li&下载依赖&/li&&li&创建 Pods.xcodeproj 工程&/li&&li&集成 workspace&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def install!
resolve_dependencies
download_dependencies
generate_pods_project
integrate_user_project
&/code&&/pre&&/div&&p&在上面的 install 方法调用的 resolve_dependencies 会创建一个 Analyzer 类的实例,在这个方法中,你会看到一些非常熟悉的字符串:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def resolve_dependencies
analyzer = create_analyzer
plugin_sources = run_source_provider_hooks
analyzer.sources.insert(0, *plugin_sources)
UI.section 'Updating local specs repositories' do
analyzer.update_repositories
end if repo_update?
UI.section 'Analyzing dependencies' do
analyze(analyzer)
validate_build_configurations
clean_sandbox
&/code&&/pre&&/div&&p&在使用 CocoaPods 中经常出现的 Updating local specs repositories 以及 Analyzing dependencies 就是从这里输出到终端的,该方法不仅负责对本地所有 PodSpec 文件的更新,还会对当前 Podfile 中的依赖进行分析:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def analyze(analyzer = create_analyzer)
analyzer.update = update
@analysis_result = analyzer.analyze
@aggregate_targets = analyzer.result.targets
&/code&&/pre&&/div&&p&analyzer.analyze 方法最终会调用 Resolver 的实例方法 resolve:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def resolve
dependencies = podfile.target_definition_list.flat_map do |target|
target.dependencies.each do |dep|
@platforms_by_dependency[dep].push(target.platform).uniq! if target.platform
@activated = Molinillo::Resolver.new(self, self).resolve(dependencies, locked_dependencies)
specs_by_target
rescue Molinillo::ResolverError =& e
handle_resolver_error(e)
&/code&&/pre&&/div&&p&这里的 Molinillo::Resolver 就是用于解决依赖关系的类。&/p&&h4&解决依赖关系(Resolve Dependencies)&/h4&&p&CocoaPods 为了解决 Podfile 中声明的依赖关系,使用了一个叫做 &a href=&/?target=https%3A///CocoaPods/Molinillo/blob/master/ARCHITECTURE.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Milinillo&i class=&icon-external&&&/i&&/a& 的依赖关系解决算法;但是,笔者在 Google 上并没有找到与这个算法相关的其他信息,推测是 CocoaPods 为了解决 iOS 中的依赖关系创造的算法。&/p&&p&Milinillo 算法的核心是 &a href=&/?target=https%3A//en.wikipedia.org/wiki/Backtracking& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&回溯(Backtracking)&i class=&icon-external&&&/i&&/a& 以及 &a href=&/?target=https%3A//en.wikipedia.org/wiki/Look-ahead_%28backtracking& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&向前检查(forward check)&i class=&icon-external&&&/i&&/a&),整个过程会追踪栈中的两个状态(依赖和可能性)。&/p&&p&在这里并不想陷入对这个算法执行过程的分析之中,如果有兴趣可以看一下仓库中的 &a href=&/?target=https%3A///CocoaPods/Molinillo/blob/master/ARCHITECTURE.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ARCHITECTURE.md&i class=&icon-external&&&/i&&/a& 文件,其中比较详细的解释了 Milinillo 算法的工作原理,并对其功能执行过程有一个比较详细的介绍。&/p&&p&Molinillo::Resolver 方法会返回一个依赖图,其内容大概是这样的:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&Molinillo::DependencyGraph:[
Molinillo::DependencyGraph::Vertex:AFNetworking(#&Pod::Specification name=&AFNetworking&&),
Molinillo::DependencyGraph::Vertex:SDWebImage(#&Pod::Specification name=&SDWebImage&&),
Molinillo::DependencyGraph::Vertex:Masonry(#&Pod::Specification name=&Masonry&&),
Molinillo::DependencyGraph::Vertex:Typeset(#&Pod::Specification name=&Typeset&&),
Molinillo::DependencyGraph::Vertex:CCTabBarController(#&Pod::Specification name=&CCTabBarController&&),
Molinillo::DependencyGraph::Vertex:BlocksKit(#&Pod::Specification name=&BlocksKit&&),
Molinillo::DependencyGraph::Vertex:Mantle(#&Pod::Specification name=&Mantle&&),
&/code&&/pre&&/div&&p&这个依赖图是由一个结点数组组成的,在 CocoaPods 拿到了这个依赖图之后,会在 specs_by_target 中按照 Target 将所有的 Specification 分组:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&{
#&Pod::Podfile::TargetDefinition label=Pods&=&[],
#&Pod::Podfile::TargetDefinition label=Pods-Demo&=&[
#&Pod::Specification name=&AFNetworking&&,
#&Pod::Specification name=&AFNetworking/NSURLSession&&,
#&Pod::Specification name=&AFNetworking/Reachability&&,
#&Pod::Specification name=&AFNetworking/Security&&,
#&Pod::Specification name=&AFNetworking/Serialization&&,
#&Pod::Specification name=&AFNetworking/UIKit&&,
#&Pod::Specification name=&BlocksKit/Core&&,
#&Pod::Specification name=&BlocksKit/DynamicDelegate&&,
#&Pod::Specification name=&BlocksKit/MessageUI&&,
#&Pod::Specification name=&BlocksKit/UIKit&&,
#&Pod::Specification name=&CCTabBarController&&,
#&Pod::Specification name=&CategoryCluster&&,
&/code&&/pre&&/div&&p&而这些 Specification 就包含了当前工程依赖的所有第三方框架,其中包含了名字、版本、源等信息,用于依赖的下载。&/p&&h4&下载依赖&/h4&&p&在依赖关系解决返回了一系列 Specification 对象之后,就到了 Pod install 的第二部分,下载依赖:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def install_pod_sources
@installed_specs = []
pods_to_install = sandbox_state.added | sandbox_state.changed
title_options = { :verbose_prefix =& '-& '.green }
root_specs.sort_by(&:name).each do |spec|
if pods_to_install.include?(spec.name)
if sandbox_state.changed.include?(spec.name) && sandbox.manifest
previous = sandbox.manifest.version(spec.name)
title = &Installing #{spec.name} #{spec.version} (was #{previous})&
title = &Installing #{spec}&
UI.titled_section(title.green, title_options) do
install_source_of_pod(spec.name)
UI.titled_section(&Using #{spec}&, title_options) do
create_pod_installer(spec.name)
&/code&&/pre&&/div&&p&在这个方法中你会看到更多熟悉的提示,CocoaPods 会使用沙盒(sandbox)存储已有依赖的数据,在更新现有的依赖时,会根据依赖的不同状态显示出不同的提示信息:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&-& Using AFNetworking (3.1.0)
-& Using AKPickerView (0.2.7)
-& Using BlocksKit (2.2.5) was (2.2.4)
-& Installing MBProgressHUD (1.0.0)
&/code&&/pre&&/div&&p&虽然这里的提示会有三种,但是 CocoaPods 只会根据不同的状态分别调用两种方法:&/p&&ul&&li&install_source_of_pod&/li&&li&create_pod_installer&/li&&/ul&&p&create_pod_installer 方法只会创建一个 PodSourceInstaller 的实例,然后加入 pod_installers 数组中,因为依赖的版本没有改变,所以不需要重新下载,而另一个方法的 install_source_of_pod 的调用栈非常庞大:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&installer.install_source_of_pod
|-- create_pod_installer
`-- PodSourceInstaller.new
`-- podSourceInstaller.install!
`-- download_source
`-- Downloader.download
`-- Downloader.download_request
`-- Downloader.download_source
|-- Downloader.for_target
|-- Downloader.class_for_options
`-- Git/HTTP/Mercurial/Subversion.new
|-- Git/HTTP/Mercurial/Subversion.download
`-- Git/HTTP/Mercurial/Subversion.download!
`-- Git.clone
&/code&&/pre&&/div&&p&在调用栈的末端 Downloader.download_source 中执行了另一个 CocoaPods 组件 &strong&CocoaPods-Download&/strong& 中的方法:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def self.download_source(target, params)
FileUtils.rm_rf(target)
downloader = Downloader.for_target(target, params)
downloader.download
target.mkpath
if downloader.options_specific?
downloader.checkout_options
&/code&&/pre&&/div&&p&方法中调用的 for_target 根据不同的源会创建一个下载器,因为依赖可能通过不同的协议或者方式进行下载,比如说 Git/HTTP/SVN 等等,组件 CocoaPods-Downloader 就会根据 Podfile 中依赖的参数选项使用不同的方法下载依赖。&/p&&p&大部分的依赖都会被下载到 ~/Library/Caches/CocoaPods/Pods/Release/ 这个文件夹中,然后从这个这里复制到项目工程目录下的 ./Pods 中,这也就完成了整个 CocoaPods 的下载流程。&/p&&h4&生成 Pods.xcodeproj&/h4&&p&CocoaPods 通过组件 CocoaPods-Downloader 已经成功将所有的依赖下载到了当前工程中,这里会将所有的依赖打包到 Pods.xcodeproj 中:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def generate_pods_project(generator = create_generator)
UI.section 'Generating Pods project' do
generator.generate!
@pods_project = generator.project
run_podfile_post_install_hooks
generator.write
generator.share_development_pod_schemes
write_lockfiles
&/code&&/pre&&/div&&p&generate_pods_project 中会执行 PodsProjectGenerator 的实例方法 generate!:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def generate!
install_file_references
install_libraries
set_target_dependencies
&/code&&/pre&&/div&&p&这个方法做了几件小事:&/p&&ul&&li&生成 Pods.xcodeproj 工程&/li&&li&将依赖中的文件加入工程&/li&&li&将依赖中的 Library 加入工程&/li&&li&设置目标依赖(Target Dependencies)&/li&&/ul&&p&这几件事情都离不开 CocoaPods 的另外一个组件 Xcodeproj,这是一个可以操作一个 Xcode 工程中的 Group 以及文件的组件,我们都知道对 Xcode 工程的修改大多数情况下都是对一个名叫 project.pbxproj 的文件进行修改,而 Xcodeproj 这个组件就是 CocoaPods 团队开发的用于操作这个文件的第三方库。&/p&&h4&生成 workspace&/h4&&p&最后的这一部分与生成 Pods.xcodeproj 的过程有一些相似,这里使用的类是 UserProjectIntegrator,调用方法 integrate! 时,就会开始集成工程所需要的 Target:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def integrate!
create_workspace
integrate_user_targets
warn_about_xcconfig_overrides
save_projects
&/code&&/pre&&/div&&p&对于这一部分的代码,也不是很想展开来细谈,简单介绍一下这里的代码都做了什么,首先会通过 Xcodeproj::Workspace 创建一个 workspace,之后会获取所有要集成的 Target 实例,调用它们的 integrate! 方法:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def integrate!
UI.section(integration_message) do
XCConfigIntegrator.integrate(target, native_targets)
add_pods_library
add_embed_frameworks_script_phase
remove_embed_frameworks_script_phase_from_embedded_targets
add_copy_resources_script_phase
add_check_manifest_lock_script_phase
&/code&&/pre&&/div&&p&方法将每一个 Target 加入到了工程,使用 Xcodeproj 修改 Copy Resource Script Phrase 等设置,保存 project.pbxproj,整个 Pod install 的过程就结束了。&/p&&h2&总结&/h2&&p&最后想说的是 pod install 和 pod update 区别还是比较大的,每次在执行 pod install 或者 update 时最后都会生成或者修改 Podfile.lock 文件,其中前者并不会修改 Podfile.lock 中&strong&显示指定&/strong&的版本,而后者会会无视该文件的内容,尝试将所有的 pod 更新到最新版。&/p&&p&CocoaPods 工程的代码虽然非常多,不过代码的逻辑非常清晰,整个管理并下载依赖的过程非常符合直觉以及逻辑。&/p&&h2&其它&/h2&&blockquote&&p&Github Repo:&a href=&/?target=https%3A///draveness/iOS-Source-Code-Analyze& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&iOS-Source-Code-Analyze&i class=&icon-external&&&/i&&/a&&/p&&p&Follow: &a href=&/?target=https%3A///Draveness& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Draveness ? GitHub&i class=&icon-external&&&/i&&/a&&/p&&p&Source: &a href=&/?target=http%3A//draveness.me/cocoapods& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&draveness.me/cocoapods&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&&/p&&/blockquote&
稍有 iOS 开发经验的人应该都是用过 CocoaPods,而对于 CI、CD 有了解的同学也都知道 Fastlane。而这两个在 iOS 开发中非常便捷的第三方库都是使用 Ruby 来编写的,这是为什么?先抛开这个话题不谈,我们来看一下 CocoaPods 和 Fastlane 是如何使用的,首先…
&img src=&/f61cff1e6f63d35b790ba_b.png& data-rawwidth=&0& data-rawheight=&0& class=&content_image& width=&0&&&p&终于等来了Growth 2.0从APP Store审核通过了,想想觉得这个过程也蛮不容易的----从最早的一篇文章开始,然后变成了一个APP,它还衍生出了两本电子书。今天它仍然再前进着,也希望它能带领大家一起前进。&/p&&h2&Web应用开发过程与Growth&/h2&&p&在那篇RePractise文章里,我们提到过Web的开发过程是这样的七个步骤:&/p&&ul&&li&前期准备&/li&&li&编码&/li&&li&上线&/li&&li&数据分析&/li&&li&持续交付&/li&&li&遗留系统&/li&&li&回顾与新架构&/li&&/ul&&p&再加上一个初学者在最开始的时候需要一些基础知识,就构成了Growth的基本内容了。&/p&&img src=&/60384dbde5_b.png& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&/60384dbde5_r.png&&&p&经历了一个又一个的项目,我们就会得到这样的经验。大部分的项目也是这样的开发过程,那么这就是很理想的学习资料了----这相当于是我们的业务,既然我们的业务已经稳定了。那么我们就可以在这之外一点点补充我们的技术即可,而这些技术并不局限于任何特有的框架和技术。&/p&&p&换句话来说,这只是一系列的理由知识。所以在第一个版本之后,人们就希望上面可以有实战的内容,还希望有一些实战项目。因此就有了两本电子书《Growth:增长工程师实战》和《Ideabook:练手项目集》,在2.0里这两本电子书也放到了里面:&/p&&img src=&/eaabb4be18adbdc72c82ebd427f9dbe0_b.png& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/eaabb4be18adbdc72c82ebd427f9dbe0_r.png&&&p&最开始的时候,在写实战这本电子书的时候我是拒绝的----不想受限于技术栈。在里面我们使用了Python语言,并使用了Django作为Web开发框架,使用Ionic作为移动应用的框架。也因此我们的开发速度相当的快,我想这也会让大家有更快的学习速度。&/p&&h2&在编程世界里探索&/h2&&p&在学习的过程中,人们需要有一些测验、有一些练手项目、还有一些发展路线,这就变成了我们的探索栏目。对于测验功能来说,要做起来倒也是容易----无非就是收集一些面试题,然后提问呗。&/p&&img src=&/dd586ea4de4a7d93cfad2_b.png& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/dd586ea4de4a7d93cfad2_r.png&&&p&对于学习路线来说,可能就不是那么容易了。需要尽可能地去收集某一个领域的技术栈,然后一一分类,再做出一些合适的判断。&/p&&img src=&/c2b8dc07f7b7d9feaf81a29_b.png& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/c2b8dc07f7b7d9feaf81a29_r.png&&&p&然后,我们还需要一些练手项目,但是现在有太多的新技术。我们还需要尽可能多地将他们一一地罗列出来:&/p&&img src=&/cc37ff63e4_b.png& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/cc37ff63e4_r.png&&&p&某个瞬间想到了自己整理的自己的工具箱也可以变成大家的工具箱,就有了这样的一个新栏目:&/p&&p&&img src=&/a302fc60dbe_b.png& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/a302fc60dbe_r.png&&当人们学习到一定的程度就想着去寻找一些解决方案了,想了想这似乎也是我擅长的内容,就有了:&/p&&img src=&/e9b9369cde6ca086e694c3_b.png& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/e9b9369cde6ca086e694c3_r.png&&&p&这个APP很快地就变成了一个Awesome Lists了。收集用户反馈在很多时候都不是一件容易的事,而在这个时候我们只能一点点的去判断。有时候,难免会做出一些错误的判断。&/p&&h2&累!&/h2&&p&很多琐事做多了也就觉得有点累,而这时候你的APP突然又有可能遭遇这样的场景!&/p&&img src=&/006ce87d771df3d52e19a6a8bc15297d_b.png& data-rawwidth=&1450& data-rawheight=&464& class=&origin_image zh-lightbox-thumb& width=&1450& data-original=&/006ce87d771df3d52e19a6a8bc15297d_r.png&&&p&还是会觉得心里有点不爽。所以,如果你觉得这个APP好,那么你就给个好评呗:&/p&&img src=&/e9682dde0d09e31b324a1c69958cbb2d_b.png& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/e9682dde0d09e31b324a1c69958cbb2d_r.png&&&p&它开源并且免费,而且数以万计的人正在使用它。&/p&&p&下载地址:&a href=&/?target=http%3A//growth.ren/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&growth.ren/&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&&/p&&p&或者在APP Store以及相应的Android应用商店搜索:Growth,或者搜索Fengda。&/p&
终于等来了Growth 2.0从APP Store审核通过了,想想觉得这个过程也蛮不容易的----从最早的一篇文章开始,然后变成了一个APP,它还衍生出了两本电子书。今天它仍然再前进着,也希望它能带领大家一起前进。Web应用开发过程与Growth在那篇RePractise文章里,我…
&img src=&/8f7f986ccba_b.jpg& data-rawwidth=&0& data-rawheight=&0& class=&content_image& width=&0&&&p&早些时候关注学习编程专栏的朋友肯定都看过了这一篇内容:&a class=&internal& href=&/p/&& 程序员把妹指南之修电脑篇&/a&&/p&&p&距离上一篇过去了挺久了,当然既然有修电脑篇就会有有其它篇的。所以今天就来实现了,不知道早些关注专栏的朋友还在不在呢。你们在哪里,番外篇来了你们等到没有。最近一段时间,经常有女生问我有关于电脑配置问题,作为程序员的你肯定也会经常被妹子问到这种问题吧。这么好接触妹子的机会,怎么能不好好把握?!不会配置电脑的程序员不是好程序员,看来我不是好程序员。&/p&&p&比如有一次学姐问我:“我想配个电脑玩GTA5,应该怎么配?”我回:“不会,不懂”。又有一次一位知乎上的妹子问我:“我学室内设计,想配置台电脑有推荐吗?”我回:“我不知道啊。” 现在想来我是不是错过了几百个亿。现在告诉我,你错过了几个亿?&/p&&p&好了,那现在我们好好打造一下配得上这个几个亿的项目。江湖老规矩,开头之前先推荐一篇十分想推荐的***,非常适合没有任何电脑配置方面知识的你(答主不会打我吧):&a href=&/question//answer/& class=&internal&&买笔记本那些五花八门的配置怎么看?都代表什么意思? - 张驰的回答&/a&&/p&&p&首先弄懂电脑配置包含哪些方面,每一方面的含义是什么包含什么怎么评价其好坏? &/p&&p&电脑的配置,是衡量一台电脑性能高低的标准。主要看CPU、显卡、主板、内存、硬盘、显示器等,以下分各个方面汇总(此部分汇总来自:&a class=& wrap external& href=&/?target=http%3A///article/1.html& target=&_blank& rel=&nofollow noreferrer&&电脑硬件知识大全 菜鸟装机必看硬件知识扫盲&i class=&icon-external&&&/i&&/a&进行了删减和添加):&/p&&p&电脑硬件知识之CPU知识篇:&br&
● &a class=& wrap external& href=&/?target=http%3A///article/6.html& target=&_blank& rel=&nofollow noreferrer&&CPU是什么 cpu是什么意思&i class=&icon-external&&&/i&&/a&?&br&
● &a class=& wrap external& href=&/?target=http%3A///article/0.html& target=&_blank& rel=&nofollow noreferrer&&CPU怎么看 怎么看CPU好坏&i class=&icon-external&&&/i&&/a&?&br&
● &a href=&/?target=http%3A///article/0.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&CPU参数的认识&i class=&icon-external&&&/i&&/a&&/p&&p&电脑硬件知识之主板知识篇&br&
● &a class=& wrap external& href=&/?target=http%3A///article/3.html& target=&_blank& rel=&nofollow noreferrer&&什么是主板 主板有什么用&i class=&icon-external&&&/i&&/a&?&br&
● &a class=& wrap external& href=&/?target=http%3A///article/2.html& target=&_blank& rel=&nofollow noreferrer&&电脑硬件知识之菜鸟必看的主板接口知识大全&i class=&icon-external&&&/i&&/a&&br&
● &a href=&/?target=http%3A///article/9.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&主板质量怎么看 如何看主板好坏&i class=&icon-external&&&/i&&/a&? &/p&&p&电脑硬件知识之内存知识篇&br&
● &a href=&/?target=http%3A///article/2.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&内存是什么 电脑内存的作用&i class=&icon-external&&&/i&&/a&&br&
● &a class=& wrap external& href=&/?target=http%3A///article/9.html& target=&_blank& rel=&nofollow noreferrer&&电脑内存怎么看 怎么看内存好坏&i class=&icon-external&&&/i&&/a&&br&
● &a class=& wrap external& href=&/?target=http%3A///article/3.html& target=&_blank& rel=&nofollow noreferrer&&物理内存与虚拟内存的区别&i class=&icon-external&&&/i&&/a&&/p&&p&电脑硬件知识之显卡知识篇&br&
● &a class=& wrap external& href=&/?target=http%3A///article/6.html& target=&_blank& rel=&nofollow noreferrer&&显卡是什么 显卡有什么用&i class=&icon-external&&&/i&&/a&?&br&
● &a class=& wrap external& href=&/?target=http%3A///article/7.html& target=&_blank& rel=&nofollow noreferrer&&怎么看电脑显卡 如何看显卡性能如何&i class=&icon-external&&&/i&&/a&&br&
● &a class=& wrap external& href=&/?target=http%3A///article/4.html& target=&_blank& rel=&nofollow noreferrer&&独立显卡和集成显卡的区别&i class=&icon-external&&&/i&&/a&&br&
● &a class=& wrap external& href=&/?target=http%3A///article/4.html& target=&_blank& rel=&nofollow noreferrer&&显卡性能怎么看 显卡主要看什么参数&i class=&icon-external&&&/i&&/a&&br&
● &a class=& wrap external& href=&/?target=http%3A///article/2.html& target=&_blank& rel=&nofollow noreferrer&&显卡显存容量与显存位宽的作用&i class=&icon-external&&&/i&&/a&&br&
● &a class=& wrap external& href=&/?target=http%3A///skill/5022.html& target=&_blank& rel=&nofollow noreferrer&&笔记本显卡怎么看&i class=&icon-external&&&/i&&/a&&br&&br&
电脑硬件知识之硬盘知识篇&br&
● &a class=& wrap external& href=&/?target=http%3A///article/8.html& target=&_blank& rel=&nofollow noreferrer&&硬盘如何分区 菜鸟必看硬盘分区教程&i class=&icon-external&&&/i&&/a&&br&&br&
电脑硬件知识之机箱电源知识篇&br&
● &a class=& wrap external& href=&/?target=http%3A///article/1.html& target=&_blank& rel=&nofollow noreferrer&&组装电脑中电脑机箱与电源选择的终极技巧&i class=&icon-external&&&/i&&/a&&br&
● &a class=& wrap external& href=&/?target=http%3A///article/1.html& target=&_blank& rel=&nofollow noreferrer&&机箱电源选购视频教程 机箱风道散热技巧&i class=&icon-external&&&/i&&/a&&br&
● &a class=& wrap external& href=&/?target=http%3A///article/9.html& target=&_blank& rel=&nofollow noreferrer&&机箱电源选购技巧 提防机箱电源里的坑爹武器&i class=&icon-external&&&/i&&/a&&/p&&p&对以上的知识有了一定的了解之后,那么你需要解答以下可能妹子会经常遇到的问题了:&/p&&p&&a class=&internal& href=&/question/&&八千元,动画专业,求电脑配置? - Autodesk Maya&/a&&/p&&p&&a class=&internal& href=&/question/&&有没有一款适合女生的配置稍好的而且不太重的电脑? - 笔记本电脑&/a&&/p&&p&&a class=&internal& href=&/question//answer/&&我学建筑专业
要涉及到CAD制图
电脑的配置方面应该如何选择?i5-4210u和74210u怎么样?显卡呢? - 知乎用户的回答&/a&&/p&&p&&a href=&/question/& class=&internal&&求一份日常家用DIY电脑配置单,预算不超过5K? - 电脑硬件&/a&&/p&&br&&p&当然还有很多妹子是不需要考虑去配置电脑的,他们大多时候只是想直接买一台电脑。这个时候就需要聪明的你去了解一下现在市面上的电脑、电脑配置以及其价格区间。&/p&&p&首先现在市场能看到的电脑品牌以及期价格区间大致有(价格仅作为参考):&/p&&blockquote&&ul&&li&联想:¥ &/li&&li&华硕:¥1900 - 49999&/li&&li&戴尔:¥1999 - 19999&/li&&li&ThinkPad:¥2599 - 74999 &/li&&li&惠普:¥1799 - 18999&/li&&li&苹果:¥5988 - 16800&/li&&li&神舟:¥1599 - 39999&/li&&li&Acer宏基:¥1699 - 19999&/li&&li&MSI微星:¥4699 - 37999&/li&&li&三星:¥1999 - 12999&/li&&li&Alienware:¥9999 - 37999&/li&&li&微软:¥4699 - 23788&/li&&li&华为:¥4988 - 9688&/li&&li&雷神:¥5099 - 15999&/li&&li&小米:¥3499 - 4999&/li&&li&机械师:¥4199 - 14999&/li&&li&机械革命:¥5599 - 15999&/li&&li&炫龙:¥2399 - 14999&/li&&li&Terrans Force:¥8500 - 50000&/li&&li&东芝:¥2899 - 16399&/li&&li&雷蛇:¥6988 - 22999&/li&&li&清华同方:¥1799 - 49999&/li&&li&海尔:¥1699 - 3799&/li&&li&火影:¥3999 - 6588&/li&&li&镭波:¥4999 - 17999&/li&&li&技嘉:¥4999 - 24999&/li&&li&宝场:¥1450 - 89999&/li&&li&富士通:¥3699 - 21999&/li&&li&麦本本:¥2799 - 6380 &/li&&/ul&&/blockquote&&p&各价格区间值得推荐的电脑(以下资料参考京东商城以及亚马逊商城,或不足请大家指出)亚马逊商城排序规则:全五星,京东商城:综合排序选出的结果如下:&/p&&p&¥:&/p&&blockquote&&ul&&li&HP 惠普 15-AC651TX 15.6英寸笔记本电脑
:¥3299&/li&&li&戴尔(DELL)成就Vostro 14VR-1528B 轻巧纤薄商务笔记本电脑:¥3299
&/li&&li&Lenovo 联想 天逸100 15.6英寸笔记本电脑:¥3099 &/li&&li&华硕(ASUS) R557LI 15.6英寸笔记本电脑:¥3199&/li&&li&Dell/戴尔 Vostro 14VR-英寸笔记本电脑:¥3499&/li&&li&戴尔(DELL)成就Vostro 14 S 商务超轻薄笔记本电脑:¥3999&/li&&li&ASUS 华硕 F455LJFSCA2X10:¥3498 &/li&&li&华硕(ASUS) 经典系列 R454LJ 14英寸笔记本:¥3299&/li&&/ul&&/blockquote&&p&¥&/p&&blockquote&&ul&&li&联想(ThinkPad )轻薄系列E450(20DCA082CD)14英寸笔记本电脑:¥4299&/li&&li&Dell/戴尔 Ins14MR-英寸质感笔记本电脑:¥4149&/li&&li&联想(Lenovo)小新700电竞版 ISK 15.6英寸超薄游戏本:¥4599&/li&&li&ASUS F555LBGCXA2X10 (华硕) F系列 多彩轻薄笔记本电脑:¥4158&/li&&li&华硕(ASUS) 飞行堡垒FX50JX 15.6英寸游戏笔记本电脑:¥4799&/li&&li&Lenovo 联想 小新310经典版 14英寸轻薄笔记本电脑:¥4173&/li&&li&华硕(ASUS) 顽石四代尊享版 15.6英寸笔记本电脑:¥4999&/li&&li&ThinkPad E460 20ETA00GCD(联想)14英寸笔记本电脑:¥4899&/li&&/ul&&/blockquote&&p&¥&/p&&blockquote&&ul&&li&ThinkPad X250-20CLA4AKCD(联想)12.5英寸笔记本电脑:¥5399&/li&&li&惠普(HP)暗影精灵II代 15.6英寸游戏笔记本:¥5499&/li&&li&Dell 戴尔 Ins17UR-2628S 17英寸笔记本电脑:¥5699&/li&&li&机械革命(MECHREVO)深海泰坦X6Ti-M2 15.6英寸游戏笔记本:¥5999&/li&&li&Samsung 三星 ATIV Book5 500R5K-Y01 白色 15.6英寸笔记本电脑:¥5498&/li&&li&Apple MacBook Air 11.6英寸笔记本电脑 银色:¥5788&/li&&li&ASUS 华硕 N系列N551JWCSC52X20 :¥5498&/li&&li&ThinkPad New S2 (20GUA004CD)13.3英寸超极笔记本电脑:¥5499&/li&&/ul&&/blockquote&&p&¥6000-&/p&&blockquote&&ul&&li&Apple MacBook Air:¥6988~&/li&&li&Apple MacBook Pro:¥10788~&/li&&li&ThinkPad X260-20F6A007CD(联想)12.5英寸笔记本电脑:¥6988 &/li&&li&ThinkPad X250-20CLA4ALCD(联想):¥6088&/li&&/ul&&/blockquote&&p& 然后再去尝试回答这两个问题:&/p&&p&&a class=&internal& href=&/question//answer/&&如何挑选一款建筑设计专业电脑? - 知乎用户的回答&/a&&br&&/p&&p&&a class=& wrap external& href=&/?target=http%3A///link%3Furl%3DjeagI6sQI1iTZPe7VeSPdYYXi9dwnsFFkF7ZHHmUPYGFtsUpWtXmkTr4yo2krIejhxKE3SYGNAvf9xWEsPw6MxhdhGFtylZ_onBgjce2xXa& target=&_blank& rel=&nofollow noreferrer&&求推荐元左右性价比高的笔记本学生党女生&i class=&icon-external&&&/i&&/a&&/p&&p&ok就到这里希望以上可以帮助到你们。&/p&&p&&b&如果你想学习编程,但是找不到学习路径和资源,欢迎关注专栏:&a class=&internal& href=&/passer&&学习编程&/a&&/b&&/p&&p&&img data-rawheight=&120& data-rawwidth=&1200& src=&/c25b866a0aa801b8fc48fa_b.png& class=&origin_image zh-lightbox-thumb& width=&1200& data-original=&/c25b866a0aa801b8fc48fa_r.png&&&a href=&/?target=http%3A//gold.xitu.io/app%3Futm_source%3Dzhihu_lurenjia%26utm_medium%3Dbanner%26utm_content%3Dgaoshou%26utm_campaign%3Dq3_zhihu& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&掘金&i class=&icon-external&&&/i&&/a&是一个高质量的技术社区,从 Swift 到 React Native,性能优化到开源类库,让你不错过互联网开发的每一个技术干货。当然你可以选择下载他们的app:点击&a href=&/?target=http%3A//gold.xitu.io/app%3Futm_source%3Dzhihu_lurenjia%26utm_medium%3Dbanner%26utm_content%3Dgaoshou%26utm_campaign%3Dq3_zhihu& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&链接&i class=&icon-external&&&/i&&/a&或者各大应用市场搜索「掘金」,技术干货尽在掌握中。赶紧去看看吧。&img data-rawheight=&500& data-rawwidth=&900& src=&/1a93f670a1ca668d951c7ff2_b.png& class=&origin_image zh-lightbox-thumb& width=&900& data-original=&/1a93f670a1ca668d951c7ff2_r.png&&&/p&
早些时候关注学习编程专栏的朋友肯定都看过了这一篇内容:距离上一篇过去了挺久了,当然既然有修电脑篇就会有有其它篇的。所以今天就来实现了,不知道早些关注专栏的朋友还在不在呢。你们在哪里,番外篇来了你们等到没有。最近一…
已有帐号?
无法登录?
社交帐号登录

参考资料

 

随机推荐