前言
非常感謝大家抽出生命中寶貴的一段時(shí)間來聽我接下來的一大段關(guān)于寫文章那些事的嘮叨。寫文章的好處看看《覺醒年代》就知道了潜秋。
這篇文章我不會(huì)寫一些常說的技巧陡舅,比如文章的內(nèi)容前后要有邏輯關(guān)系纵潦,內(nèi)容之間有關(guān)聯(lián)偶房。所講知識(shí)前后的層次要平摆寄,不要在某個(gè)部分挖掘過深失暴。寫作過程中牢牢抓住要表達(dá)的內(nèi)容,不要過于偏離主題微饥。類似這樣的技巧不會(huì)說逗扒。都說一流的人討論思想、普通人討論事情欠橘、三流的人討論人矩肩,那么為了提高文章高度,除了說些事情肃续,我還打算加些思想的內(nèi)容黍檩。
大家都習(xí)慣去閱讀他人人生體驗(yàn)來體驗(yàn)不一樣的人生,這樣的方式和評(píng)頭論足一樣簡單舒服始锚,輕松爽快刽酱。而主動(dòng)去對(duì)自己思想進(jìn)行研究和開發(fā),通過寫作輸出自己獨(dú)特的經(jīng)歷和思考卻是困難且難受的瞧捌,但這樣從0到1和從0到10的創(chuàng)造過程獲得的樂趣卻是前者的百倍甚至更多孵奶,這背后所遵循的原則是怎樣的呢交煞?
每個(gè)心得都會(huì)基于某些原則,以至于思路不會(huì)散架,而所有的原則都無法違背物熱力學(xué)第二定律怀浆,也就是熵增定律(強(qiáng)烈建議先看知乎這篇介紹)。就連進(jìn)化論都是遵循熵增定律识樱。
對(duì)于寫作的心得我提煉出獨(dú)特性火的、真實(shí)感、故事性和新意四個(gè)點(diǎn)麦轰,其中的獨(dú)特性和新意都是逆著熵增的過程乔夯,其過程是非常難受煎熬的砖织,可能做了大量付出也沒結(jié)果,因?yàn)槟骒卦鍪欠蔷€性的末荐,無法預(yù)測的侧纯,只有在偶然的機(jī)會(huì)才會(huì)有開掛的感覺。對(duì)于真實(shí)感和故事性屬于線性積累甲脏,和閱讀別人的文章一樣眶熬,是很容易做到的事情,都是熵增過程块请,有必要娜氏,容易看到結(jié)果,但會(huì)有內(nèi)耗墩新,如果沒有更多獨(dú)特性的經(jīng)歷來逆熵贸弥,可輸出的內(nèi)容會(huì)越來越混亂,落后海渊,漸漸無用绵疲。因此獨(dú)特性、真實(shí)感臣疑、故事性和新意這四個(gè)點(diǎn)之間需要平衡與演進(jìn)盔憨,才能夠保持進(jìn)化的活力。
接下來我就詳細(xì)展開來跟你說說獨(dú)特性讯沈、真實(shí)感郁岩、故事性和新意四個(gè)點(diǎn),通過我以前寫的一些文章來詳細(xì)說明缺狠。如果你還不知道如何下筆驯用,我還會(huì)介紹一個(gè)容易著手去做記錄和分享輸出的方法步驟,最后會(huì)從頭到尾舉個(gè)例子按照前面介紹的步驟演示如何寫完一篇技術(shù)文章儒老。特別是那些逆熵的過程蝴乔,讓你能夠多些體感。
四個(gè)點(diǎn)
先分別介紹下這四個(gè)點(diǎn)驮樊。
獨(dú)特性
獨(dú)特性也就是自己的經(jīng)歷和體驗(yàn)薇正,這個(gè)是獨(dú)一無二的,文章的內(nèi)容如果有更多的個(gè)人經(jīng)歷囚衔,作為讀者也就能夠體驗(yàn)到更多的生活挖腰。
行萬里路,多去做不同事情练湿,多嘗試不同方法猴仑,也就能夠獲取到更多的經(jīng)歷。獨(dú)特性是內(nèi)容中最重要的部分,如果這四點(diǎn)重要性共分十層的話辽俗,我認(rèn)為獨(dú)特性就可以占到六層疾渣。
真實(shí)感
記得一個(gè)美劇編劇分享過他寫編劇的經(jīng)驗(yàn),其中提到要寫的題材崖飘,他至少會(huì)花上一年以上的時(shí)間去收集和整理相關(guān)資料榴捡。他認(rèn)為只有把題材相關(guān)細(xì)節(jié)都吃透了,編排到劇里朱浴,觀眾才會(huì)感覺更真實(shí)吊圾,代入感才會(huì)強(qiáng),身同感受才會(huì)有共鳴翰蠢。如果觀眾感到假项乒,感覺不到用心,那他怎么會(huì)去了解你想表達(dá)的內(nèi)容呢梁沧。
因此真實(shí)感是表達(dá)內(nèi)容的基礎(chǔ)檀何,而且是最費(fèi)時(shí)的。相較于獨(dú)特的個(gè)人經(jīng)歷趁尼,真實(shí)感是需要花費(fèi)大量時(shí)間去調(diào)研作者以前不了解的東西埃碱。而這個(gè)過程也是了解別人經(jīng)歷的過程猖辫,可以學(xué)習(xí)到很多以前不知道的事情酥泞。
真實(shí)感是對(duì)獨(dú)特性的擴(kuò)充,是豐富和挖掘沉淀獨(dú)特性的啃憎,可以占到兩層芝囤,后面的故事性和新意各占一層。
故事性
我很喜歡金庸的小說辛萍,特別是射雕英雄傳悯姊、神雕俠侶和倚天屠龍記這三部,起初對(duì)金庸其它小說興趣不大贩毕,也可能拍的電視劇不是我的菜悯许。后來抱著愛屋及烏的態(tài)度,我嘗試著打開笑傲江湖小說的開頭開始讀辉阶,一下子就被吸引進(jìn)去了先壕。不得不佩服金庸寫故事的能力,太強(qiáng)大了谆甜。故事一開始制造了一個(gè)令人無法解釋的案件垃僚,你會(huì)非常好奇的一直看下去,很想知道到底發(fā)生了什么规辱。小說都進(jìn)行了很長的部分令狐沖才出現(xiàn)谆棺,主角出現(xiàn)前還能吸引你看下去,可見金庸講故事能力有多厲害罕袋。
自從迷上金庸的小說后改淑,我也會(huì)試著寫些小故事碍岔,同樣我會(huì)注重把一些自身獨(dú)特的經(jīng)歷穿插到寫的小故事里,這些故事我發(fā)到了我的博客上溅固,有白龍班付秕、十中、白羋和花野
故事性是一種技巧侍郭,是線性的询吴,很容易通過大量積累掌握好,最終是好是差還是強(qiáng)依賴于獨(dú)特性和真實(shí)感亮元。
新意
新意這個(gè)點(diǎn)非常關(guān)鍵和重要猛计,也是演進(jìn)的重要因素,你仔細(xì)想想看爆捞,很多深度高的文章其實(shí)底層知識(shí)都是差不多的奉瘤,能夠真正有翻天覆地突進(jìn)的技術(shù)演進(jìn)不會(huì)很頻繁,而且這些技術(shù)往往都在硬件廠商和實(shí)驗(yàn)室中產(chǎn)生出來煮甥。對(duì)于已有底層知識(shí)的輸出區(qū)別只是應(yīng)用場景和組合運(yùn)用技巧上有區(qū)別盗温,精彩的發(fā)掘和效果奇佳的收益也能夠獲得掌聲。因此技術(shù)知識(shí)和經(jīng)驗(yàn)輸出的形式也非常重要和關(guān)鍵成肘,如果沒有新意卖局,大家勢必會(huì)對(duì)那些知識(shí)感覺到疲倦,沒人看双霍,寫作也就沒有了動(dòng)力砚偶。
關(guān)于新意可以看到淘系公眾號(hào)最近使用了視頻的方式來講他們的技術(shù),看起來就很有趣洒闸。這方面只有你想不到染坯,沒有你做不到,打開腦殼丘逸,充分發(fā)揮想象吧单鹿。
新意之所以只占一層,因?yàn)樾乱猥@得成功的概率較低深纲,是非線性的仲锄,因此需要不斷去嘗試不同的方式。需要依賴天時(shí)地利人和以及前三個(gè)點(diǎn)都做的足夠好了囤萤,新意才會(huì)取得非常好的效果昼窗。
我以前的文章
前面講了四個(gè)我覺得寫技術(shù)文章最重要的點(diǎn),只是說了下理論上的邏輯涛舍,體感還不夠強(qiáng)澄惊,下面我結(jié)合我以前寫的文章我們一起來看看這些文章背后那些獨(dú)特的經(jīng)歷吧。
A站 的 Swift 實(shí)踐
《A站 的 Swift 實(shí)踐》上、下掸驱,當(dāng)時(shí)發(fā)這篇文章時(shí)肛搬,關(guān)于 Swift 實(shí)踐的文章也有很多,都是各廠自身實(shí)踐經(jīng)驗(yàn)毕贼,對(duì)于獨(dú)特性這個(gè)點(diǎn)温赔,開始想著把 A 站做過的事情說清楚就可以了,但是很多的經(jīng)驗(yàn)和做的事情和其他廠做的差不多鬼癣,這樣寫出來會(huì)沒有什么特別的陶贼,所以需要著重說下做的和別人不一樣的事情。A站比較有特色的是文章里提到的A站自研的聲明式 UI Ysera 框架待秃,這個(gè)是別人沒有的拜秧,并且由于 Ysera 框架帶來了和 SwiftUI 類似的優(yōu)雅簡潔,提升了整體開發(fā)的效率和體驗(yàn)章郁。由于 A 站很早就進(jìn)入了 Swift 開發(fā)模式枉氮,并且已有將近一半業(yè)務(wù)使用了 Swift 開發(fā),所以 A 站相較其它廠走得更快些暖庄,對(duì)于 Swift 新特性運(yùn)用的也更廣聊替,比如對(duì)于 Property Wrapper 的廣泛應(yīng)用,使得代碼復(fù)雜度驟然降低培廓。走得更遠(yuǎn)還表現(xiàn)在 Module 化上惹悄,A 站大半 Pod 都完成了 Module 化,這方面的經(jīng)驗(yàn)也很多医舆。
有了獨(dú)特性俘侠,為了能夠讓閱讀的人更有體感象缀,需要對(duì)一些技術(shù)點(diǎn)進(jìn)行進(jìn)一步的描述蔬将,使得文章一方面能夠讓自己得到知識(shí)的總結(jié)沉淀,還能夠?qū)λ擞杏醚胄恰_@篇文章主要是在混編的內(nèi)在原理上進(jìn)行了剖析霞怀,這比只描述解決混編問題過程要更加通用些,同時(shí)也能起到授人以漁的目的莉给。但掌握原理就需要去學(xué)習(xí)和提煉相關(guān)知識(shí)毙石,所下的功夫也更大些。另外采用 Swift 的話颓遏,還有個(gè)繞不過去的擔(dān)憂點(diǎn)需要面對(duì)徐矩,這就是 Swift 的動(dòng)態(tài)性,Swift 這方面由于在 Swift 核心團(tuán)隊(duì)工作優(yōu)先級(jí)中較低叁幢,相較于 OC 要弱和不成熟很多滤灯。所以關(guān)于動(dòng)態(tài)化就要說清楚,說的全面點(diǎn),最好是能夠自己進(jìn)行實(shí)驗(yàn)去驗(yàn)證鳞骤,這個(gè)過程會(huì)往往枯燥漫長窒百,需要較大的熱情才能夠完成。
關(guān)于故事性豫尽,故事性往往是用來引入讀進(jìn)去的一種辦法篙梢,A 站的 Swift 實(shí)踐這篇文章的開頭通過講述使用 Swift 的必要性、A 站為之付出的努力和收獲美旧、Swift 語言的演進(jìn)的過程的方式盡量避開具體技術(shù)描述渤滞,而是使用通俗易懂的描述讓讀的人可以被輕松帶入到文章中來。
深入剖析Auto Layout榴嗅,分析iOS各版本新增特性
《深入剖析Auto Layout蔼水,分析iOS各版本新增特性》。寫這個(gè)文章也是有著一段不同尋常的經(jīng)歷录肯。那時(shí)剛到公司趴腋,所有布局都還是使用的 frame 方式,而 Auto Layout 蘋果公司才推出不久论咏,在另一位跟我一樣新進(jìn)公司熟悉 Auto Layout 同事的慫恿下优炬,我打算在改版需求中使用 Auto Layout 來替換原有布局方式。但在需求開發(fā)剛開始時(shí)厅贪,那位熟悉 Auto Layout 的新同事突然離職了蠢护,我感覺失去了援手,但是我認(rèn)可了這個(gè)技術(shù)养涮,還是堅(jiān)持使用它葵硕。期間碰到的苦難無數(shù),布局思路帶來了很多開發(fā)方式的改變贯吓,還有動(dòng)畫的結(jié)合會(huì)出現(xiàn)的各種效果不一致懈凹,其間公司老員工還不斷勸我還是走老路比較穩(wěn)妥。改版完后大部分主流程悄谐,包括首頁發(fā)單介评、等待頁、接單進(jìn)行頁都被改造成 Auto Layout爬舰。
更困難的事情還在后面呢们陆,測試期間發(fā)現(xiàn)在 iOS6 上會(huì)出現(xiàn)各種崩潰、頁面布局混亂情屹、動(dòng)畫效果不一致等問題坪仇,我的 Bug 始終保持在 Bug 列表前十頁。改 Bug 那些天垃你,晚上調(diào)的眼發(fā)疼椅文,深夜想的難入眠颈墅。線下 Bug 改完,上線后才是噩夢的開始雾袱,當(dāng)時(shí)我們 App 的 iOS6 用戶依舊很多恤筛,于是很多偶現(xiàn)崩潰被放大了,我的崩潰問題一直排在 Top1芹橡,雖然我很快找到了改好的辦法毒坛,但是對(duì)于這幾個(gè)偶現(xiàn)的問題還需要一個(gè)可靠可信服的解釋,這樣后面才能夠讓大家放心使用 Auto Layout林说。還記得當(dāng)時(shí)周末坐在得實(shí)大廈窗戶邊的工位上煎殷,在查完和試完所有資料后依然無果時(shí)的無力感。本想著改回以前的 frame 布局算了腿箩,后又覺不甘豪直。下幾個(gè)周末跑到各大圖書館查看所有涉有 Auto Layout 的書,也是那個(gè)時(shí)候了解到了 VFL 語言珠移」遥皇天不負(fù)有心人,WWDC 開始了钧惧,其中有個(gè) Session 叫 Mysteries of Auto Layout暇韧,分為上、下兩個(gè)部分浓瞪,把 Auto Layout 的原理講得非常透徹了懈玻,至此,透過原理我也找到了問題的根因乾颁,并把他們記錄在了文章中涂乌。這部分內(nèi)容我還在一個(gè)沙龍做了分享,下面是當(dāng)時(shí)分享的 Auto Layout 的原理部分的內(nèi)容:
完整幻燈片參看這里英岭。
這些經(jīng)驗(yàn)的總結(jié)在當(dāng)時(shí)是非常新的湾盒,因?yàn)楣俜揭彩莿偣汲銎鋬?nèi)部的原理,沒有人能夠更早的知道這些信息巴席,估計(jì)也很少有人會(huì)考究這么多历涝。有了這些由于一直堅(jiān)持下來去找根因的經(jīng)歷才使得文章有了獨(dú)特性诅需。
當(dāng)然漾唉,深入剖析 Auto Layout 這篇文章也加了 Auto Layout 的歷史、生命周期堰塌、VFL 語言的介紹用來豐富內(nèi)容的廣度赵刑,以提升真實(shí)感,但你會(huì)發(fā)現(xiàn)獨(dú)特性在這里顯得尤為重要场刑。
另外般此,在查找崩潰問題根因時(shí)蚪战,沒有放棄,一直堅(jiān)持的去找答案的過程也讓我難忘铐懊。經(jīng)常會(huì)聽說到要去找自己熱愛的事情邀桑,遵循自己所想。而實(shí)際上是那件熱愛的事情是你愿意花很久甚至很多年需要克服痛苦科乎,還能夠繼續(xù)忍耐壁畸,能忍他人所不能忍,贏過他人不是靠的熱愛和能力茅茂,而是在萬般艱難捏萍,別人都放棄而你堅(jiān)持下來才贏的。巴菲特21年資產(chǎn)5000億美元空闲,其中4997億美元是50歲之后賺到的令杈,如果49歲那年他就不繼續(xù)做了,那么他就不會(huì)有今年這樣巨大的財(cái)富碴倾,就不會(huì)顯示巨大的復(fù)利效應(yīng)逗噩。
后來我還發(fā)現(xiàn),不斷堅(jiān)持的一個(gè)竅門就是去慶祝大目標(biāo)方向上的每個(gè)小小的成功跌榔,把這個(gè)小小的成功當(dāng)成最后的成就那樣去慶祝给赞。
制作一個(gè)類似蘋果VFL(Visual Format Language)的格式化語言來描述類似UIStackView那種布局思路,并解析生成頁面
這篇文章 誕生的原因是我寫了一個(gè)視圖布局的庫 AssembleView矫户,通過這篇文章做了一個(gè)記錄片迅。這篇的獨(dú)特性在于文章背后我特殊的經(jīng)歷。首先寫 AssembleView 的起因在于之前大半年我使用自動(dòng)布局寫了大量的頁面和一些動(dòng)畫皆辽,雖然有比系統(tǒng)更加簡化的 Masonry 庫可以使用柑蛇,但是對(duì)于很早以前寫過 H5 頁面的我來說無論是從布局思路還有編寫體驗(yàn)上,Masonry 依舊差的很遠(yuǎn)驱闷。蘋果為自動(dòng)布局發(fā)明的簡潔 VFL 語言卻沒能用在更加先進(jìn)的 UIStackView 布局思路上耻台,于是在一次中午吃飯散步的過程中,我突然有了把 VFL 語言和 UIStackView 布局結(jié)合起來的想法空另,同時(shí)還想好了名字盆耽,叫做 AssembleView,也就是組裝的視圖的意思扼菠,心動(dòng)不如行動(dòng)摄杂,在接下來的一個(gè)需求周期中,我就著手一邊開發(fā) AssembleView 一邊開發(fā)需求循榆。每個(gè)需求只有一周的開發(fā)時(shí)間主卫,當(dāng)時(shí)需求只是更新評(píng)價(jià)的幾個(gè)小頁面部件胰耗,但為了將 AssembleView 運(yùn)用進(jìn)來岖赋,我把整個(gè)評(píng)價(jià)頁面和功能進(jìn)行了重寫,包括標(biāo)簽云等復(fù)雜布局采用新庫的重寫泽篮。而這樣的工作量僅在一周內(nèi)完成了。
短時(shí)間完成 AssembleView 并應(yīng)用到產(chǎn)品中柑船,得益于 Deadline 的限制帽撑,設(shè)置時(shí)間節(jié)點(diǎn),沒有時(shí)間節(jié)點(diǎn)的目標(biāo)那就是夢想鞍时,有了時(shí)間節(jié)點(diǎn)會(huì)讓你保持一段時(shí)間專注油狂,在限制的時(shí)間里,你沒法去把事情做到方方面面都好寸癌,因此才會(huì)激發(fā)你专筷,讓你發(fā)揮自身的獨(dú)特性,和別的不同蒸苇,其實(shí)這種獨(dú)特會(huì)讓這件事情完成的更有價(jià)值磷蛹。不要試著做最好的,而是力求做與眾不同的溪烤。與眾不同意味著創(chuàng)新味咳,畫草圖和下筆寫稿子都是創(chuàng)造的方式,這些過程不要去做雕琢檬嘀、檢查槽驶、取舍、反思這樣的事情鸳兽,而是釋放自己的本能掂铐,去自由的發(fā)揮自己的積累和沉淀。藝術(shù)總是來自不完美揍异,始于雜亂全陨。
有了這樣非同尋常的經(jīng)歷,使得這篇文章本身獨(dú)特性的意義更大了衷掷。記錄并分享辱姨,能夠獲得做著同樣事情人的共鳴。
AssembleView 本身就是全新戚嗅,因此從頭到尾都是新意雨涛。
當(dāng)時(shí)寫這個(gè)庫也是為了能夠提高完成需求和維護(hù)需求的時(shí)間,有了精力才能夠做更有趣有意義的事情嘛懦胞。五年后替久,蘋果終于將 VFL 這種 DSL 語言運(yùn)用 Swift 強(qiáng)大的 ResultBuilder 和不透明類型等特性進(jìn)行了更好地完善,配合 Property Wrapper 和 Combine 還無縫銜接了先進(jìn)的數(shù)據(jù)流架構(gòu)医瘫,推出了 SwiftUI侣肄。
深入剖析 JavaScriptCore
《深入剖析 JavaScriptCore》 這篇文章要說獨(dú)特性,那就是對(duì) JavaScript 語言的好奇心醇份。我很早就開始使用 JavaScript 來開發(fā)網(wǎng)站稼锅,工作和個(gè)人網(wǎng)站的前端都是依賴于這門語言,其實(shí)知情人都知道僚纷,選擇 JavaScript 也是沒有選擇的選擇矩距。年輕時(shí)只顧著使用技術(shù)去做東西,也做了自己覺得非常有趣的程序怖竭,滿足感十足锥债,現(xiàn)在轉(zhuǎn)向?qū)ζ浔澈蟮臋C(jī)制技術(shù)好奇和感興趣了。還有一個(gè)迫使自己去了解 JavaScript 引擎的原因是工作中做動(dòng)態(tài)頁面時(shí)需要用到對(duì)業(yè)務(wù)邏輯的解釋執(zhí)行處理痊臭。為了避免使用中出了問題會(huì)一臉懵哮肚,深入了解它顯得很有必要。
光有想法是沒有一點(diǎn)用的广匙,JavaScriptCore 其實(shí)非常的龐大且復(fù)雜允趟,當(dāng)時(shí)能找到的大部分資料都是 Bridge 和 RN 的運(yùn)用,好在開源了鸦致,了解內(nèi)部的話還可以拉代碼來看潮剪。但是直接埋進(jìn)去看代碼,代碼量比較大分唾,很容易 miss 掉其精妙之處抗碰。好在發(fā)現(xiàn)了 JavaScriptCore 項(xiàng)目核心開發(fā)者 Filip Pizlo,通過他的個(gè)人網(wǎng)站找到了大量 JavaScriptCore 的一手資料绽乔,沒日沒夜的啃內(nèi)容弧蝇,同時(shí)還試著動(dòng)手去實(shí)現(xiàn)一些技術(shù)細(xì)節(jié),最終了解和學(xué)習(xí)了很多解釋器折砸、虛機(jī)相關(guān)知識(shí)捍壤。獲取一樣?xùn)|西帶來的滿足感是沒有獲取經(jīng)驗(yàn)帶來的滿足感更深刻。我把學(xué)到的這些經(jīng)驗(yàn)都記錄在了這篇文章中鞍爱,這使得文章的獨(dú)特性更加深刻鹃觉,真實(shí)感達(dá)到了滿棚。
深入剖析 JavaScript 編譯器/解釋器引擎 QuickJS - 多了解些 JavaScript 語言
對(duì)于 JavaScript 引擎睹逃,我先前就看了 JavaScriptCore盗扇,為啥還要再去看 QuickJS 這個(gè)輕量的 JavaScript 引擎呢。寫這篇文章動(dòng)力主要還是對(duì)QuickJS如何使用精簡高效的代碼實(shí)現(xiàn)了那么復(fù)雜功能沉填,還有極高的性能疗隶。QuickJS 基本是從頭看到尾,一點(diǎn)一點(diǎn)的分析翼闹,整個(gè)過程也都記錄了下來斑鼻。但是我覺得記錄源碼的分析還不夠,雖然這些分析使得文章的真實(shí)感很高猎荠,前提是讀的人也會(huì)埋進(jìn)代碼里坚弱。為了提高文章的獨(dú)特性和故事性蜀备,我在文章開頭加入了一些 JavaScript 的一些背景內(nèi)容,還有些當(dāng)年使用前端技術(shù)的體會(huì)和經(jīng)驗(yàn)荒叶。
只看代碼不去修改和調(diào)試碾阁,往往會(huì)很枯燥,我在分析代碼前些楣,也寫了些和 QuickJS 工程配置 makefile 相關(guān)的內(nèi)容脂凶,并以 QuickJS 本身的 makefile 的用法進(jìn)行舉例說明。另外還手把手說明了怎么用 Xcode 來編譯安裝調(diào)試 QuickJS 代碼愁茁,這些都是比較獨(dú)特的內(nèi)容蚕钦。QuickJS 的核心代碼基本都寫在一個(gè)文件里,閱讀分析時(shí)需要非常的專注鹅很,如果不專注嘶居,可能這篇文章也就沒法寫完。如果你花大量時(shí)間在家玩游戲道宅、看電視劇和刷短視頻食听,而不工作,那么就會(huì)有危機(jī)感和負(fù)罪感污茵。但是如果會(huì)去工作樱报,但是期間總會(huì)找著間隙去做其他事情,刷刷微博泞当,看看朋友圈迹蛤,瞅瞅新聞什么的,那就不會(huì)有負(fù)罪感襟士,因?yàn)槟銜?huì)覺得你還是在工作著呢盗飒。沒全力去工作,而在假裝工作著陋桂,可比完全不工作的危害更大逆趣。一心一意的長時(shí)間去做工作外的事情,反而能夠開眼界擴(kuò)視野嗜历,從而反哺工作宣渗,工作的更好更開心。新時(shí)代就會(huì)有新機(jī)會(huì)梨州,同時(shí)也會(huì)有新的要求痕囱,比如知識(shí)的獲取從單一感官方式變成了動(dòng)態(tài)的,多感官的方式暴匠。以前只是文字和圖片的書和博客鞍恢,新時(shí)代就是視頻、直播和播客,新時(shí)代你有更多方式出現(xiàn)在大家面前帮掉,出現(xiàn)的更多就代表了成功弦悉。未來會(huì)有更多感官方式,而且更加的智能旭寿。獲取知識(shí)的門檻低了警绩,人群也就更廣了崇败,也可以理解為新的機(jī)會(huì)更大了盅称,保持專注不設(shè)限去感受新時(shí)代,對(duì)自己不斷做出新的要求后室,就會(huì)有新的機(jī)會(huì)缩膝。
深入剖析 iOS 編譯 Clang / LLVM
寫這篇文章的原因主要來自在公司做的 App 安裝包體積瘦身的事情,經(jīng)過各種工具使用和分析后岸霹,總是找不到突破口疾层。需求還在不斷疊加,也沒有好的思路贡避。當(dāng)你遇到困難時(shí)痛黎,做不成的人才會(huì)告訴你你也做不成,如果你真的想做成刮吧,有這個(gè)理想就要自己去守護(hù)他湖饱。遇到困難離成功才會(huì)更接近。那些困難來自于有限的資源杀捻,比如沒人井厌、沒錢等,但是正是由于這些資源的限制致讥,才會(huì)迫使你去創(chuàng)新仅仆,你會(huì)通過自己的熱情還有毅力來尋找獨(dú)特更有效的方法,所以由于有限資源帶來的困難才會(huì)讓你去突破垢袱、思變和進(jìn)取墓拜。
就在百般無奈,各種資源條件受限的情況下请契。我想著看能不能把需要繁瑣手動(dòng)檢查的動(dòng)作試著寫成程序自動(dòng)完成咳榜。于是我用一個(gè)周末開發(fā)了查找無用方法工具,能夠自動(dòng)查找出工程中沒有用到的方法姚糊,也兼顧了我們工程的一些運(yùn)行時(shí)調(diào)用的方法檢查贿衍。這樣重復(fù)繁重的檢查工作就變得輕松了很多。
工具開發(fā)完后救恨,我發(fā)現(xiàn)這工具的實(shí)現(xiàn)并無相關(guān)成熟理論來進(jìn)行支持贸辈,以后怎么完善和優(yōu)化這個(gè)工具也沒有一點(diǎn)思路。為此我還苦惱了蠻久的。
經(jīng)過一位同事提醒擎淤,說大學(xué)有門編譯原理的課里面就有講怎么分析代碼的奢啥,于是我就開始針對(duì)性的翻閱相關(guān)資料。于是乎嘴拢,我發(fā)現(xiàn)了一片藍(lán)海桩盲,這里面涉及到的技術(shù)不光是分析代碼,還有很多以前不了解的程序怎么跑起來的細(xì)節(jié)席吴,這里的知識(shí)就像可以無限遞歸的樹赌结,能夠?qū)⒛闼袝r(shí)間都吞沒。這篇文章我更新添加內(nèi)容的次數(shù)不下十次孝冒,每當(dāng)get到了新的東西都忍不住記錄下來柬姚。這期間動(dòng)手去實(shí)踐一些知識(shí)點(diǎn),也遇到很多問題庄涡,解決這些問題的過程量承,對(duì)相關(guān)知識(shí)理解就更深入了。后來在17年的@Swift 大會(huì)上還做了 LLVM 相關(guān)內(nèi)容的分享穴店,下圖是其中一張 Slide撕捍。
完整幻燈片參看這里
深入剖析 WebKit
為了完成網(wǎng)頁到原生代碼的轉(zhuǎn)換,我開始學(xué)習(xí) Web 的標(biāo)準(zhǔn)泣洞,而 WebKit 是蘋果公司對(duì) Web 標(biāo)準(zhǔn)實(shí)現(xiàn)忧风,V8和 Flutter 渲染技術(shù)的源頭,WebKit 的學(xué)習(xí)能夠讓我更完整的了解網(wǎng)頁從請(qǐng)求到布局再到渲染的流程和使用的相關(guān)技術(shù)斜棚。WebKit的這篇文章我羅列了大量的 Web 規(guī)范資料阀蒂,由于 WebKit 非常的龐大,架構(gòu)也很復(fù)雜弟蚀,文章里對(duì)架構(gòu)也進(jìn)行了詳細(xì)的說明蚤霞,對(duì)源碼的結(jié)構(gòu)做了詳細(xì)的說明。全文按照一個(gè)頁面從請(qǐng)求到最終渲染的流程順序义钉,依次對(duì)其關(guān)鍵環(huán)節(jié)里對(duì)應(yīng)源代碼和原理進(jìn)行了詳細(xì)的說明昧绣。完成這篇花費(fèi)時(shí)間巨大,代碼基本讀了個(gè)遍捶闸。之后我對(duì)于前端技術(shù)有了更深的理解夜畴,特別是頁面異步加載的流程和布局原理。
感覺這篇完全靠的是對(duì)前端技術(shù)的熱情完成的删壮。手冢治蟲說過贪绘,那些投稿的人,都是熱愛著漫畫央碟,把畫出一部作品作為自己生命意義的人税灌。所以他們才能獲得成功,成為馬拉松里跑到最后的人。熱情可以增加25個(gè) IQ 值菱涤。如果一個(gè)人仿佛開悟了的高僧苞也,失去任何欲求、愿望粘秆、不甘如迟、煩恨與傷痛,那么即使他去畫漫畫攻走,即使基因再好殷勘,天賦再高,也只會(huì)畫成佛教的禪畫罷了陋气。在比爾.布萊森在《人體簡史》這本書中提到一個(gè)鏡子相關(guān)的實(shí)驗(yàn)劳吠,實(shí)驗(yàn)來自一名防碎眼鏡商人引润,在1980年創(chuàng)辦了胚種精選擇庫(Repository for Germinal Choice)巩趁,這個(gè)精子庫只有諾貝爾獲獎(jiǎng)?wù)吆推渌艹鲋R(shí)權(quán)威的鏡子。他想的是能夠提供最好的精子生出天才嬰兒淳附,結(jié)果是在出生的200名兒童里议慰,沒有一個(gè)杰出天才,甚至連一個(gè)眼鏡工程師都沒能造出來奴曙,可見對(duì)做的事情有熱情更加重要别凹,而不僅僅只要基因好就行。
深入剖析 iOS 性能優(yōu)化
性能這篇最重要的是獨(dú)特性洽糟,開始只是針對(duì)日常開發(fā)性能需要注意的一些點(diǎn)進(jìn)行了歸納總結(jié)炉菲,后來需要對(duì)啟動(dòng)項(xiàng)進(jìn)行分析,于是做了分析的工具坤溃,其間我無意多查看了下 thread_basic_info_t 這個(gè)結(jié)構(gòu)體里的字段拍霜,發(fā)現(xiàn)了 cpu_usage,覺得日后必有用薪介,于是留了個(gè)心眼祠饺。后來負(fù)責(zé)性能的同學(xué)看了我的這篇文章,跑來找我汁政,跟我說 App 連續(xù)幾個(gè)版本都有線上反饋耗電太大道偷,他們自己也很容易復(fù)現(xiàn)出來。這幾個(gè)版本調(diào)整了定位頻率记劈,排查了各種懷疑的點(diǎn)勺鸦,電量消耗依然很大。起初我也沒有思路目木,instruments 也看不出問題來换途,于是我使用分析啟動(dòng)項(xiàng)的方法,查看運(yùn)行中方法調(diào)用次數(shù),排序來看誰調(diào)用的頻繁怀跛,后來發(fā)現(xiàn)調(diào)用頻繁的方法數(shù)量太多很難排查定位距贷。
這時(shí)先前留意的 cpu_usage 字段起來關(guān)鍵的作用,通過定時(shí)刷新獲取線程中 CPU 使用情況吻谋,連續(xù)高使用就揪出詳細(xì)線程堆棧忠蝗,后來小范圍灰度上線檢測,直接定位到了問題的堆棧漓拾,很快的解決了這個(gè)大難題阁最。而且有了這個(gè)手段,后面也有了底氣骇两,在遇到問題也不會(huì)慌了速种,而且線下也可以使用這個(gè)方法進(jìn)行壓力測試,以免把問題帶到了線上低千。這個(gè)方案也更新記錄到了文章中配阵,有了這個(gè)不尋常的經(jīng)歷,文章也就有了很強(qiáng)的獨(dú)特性示血。
啟動(dòng)
關(guān)于啟動(dòng)我寫了兩篇文章棋傍。第一篇是《如何對(duì) iOS 啟動(dòng)階段耗時(shí)進(jìn)行分析》,另一篇是《App 啟動(dòng)提速實(shí)踐和一些想法》难审。說起這兩篇的獨(dú)特性瘫拣,那絕對(duì)是獨(dú)一無二。我負(fù)責(zé)的這場血淋淋的戰(zhàn)役真可以說是畢生難忘告喊。項(xiàng)目起因不用猜也可以想到麸拄,啟動(dòng)速度持續(xù)劣化,導(dǎo)致用戶體驗(yàn)變差黔姜,落后對(duì)手一倍拢切,提速困難重重。臨危受命地淀,當(dāng)時(shí)想到的只有一個(gè)字失球,那就是干。
開始最難的還是定方向和定策略以及決策帮毁。明確了整體的思路实苞,所有任務(wù)就開始并行跑起來了。由于項(xiàng)目的重要性不言而喻烈疚,因此投入資源巨大黔牵,不光是我的人都參與了進(jìn)來,還有很多其他團(tuán)隊(duì)也一起加入爷肝。停下所有手上低優(yōu)事情猾浦,握緊拳頭全力打贏關(guān)鍵戰(zhàn)役陆错。要的就是能夠速戰(zhàn)速?zèng)Q,一旦拖延金赦,不光是士氣沒了音瓷,結(jié)果沒達(dá)成,還會(huì)留下一堆爛攤子難有資源去清理夹抗。
由于初期謀劃的方案全面绳慎、稠密以及有效,多個(gè)團(tuán)隊(duì)通力合作配合奇佳漠烧,使得在三周內(nèi)超預(yù)期達(dá)成了目標(biāo)杏愤,不光是領(lǐng)先了對(duì)手一倍,還比大部分頭部 App 都要快已脓。這三周說長不長珊楼,說短也不短,大量的開發(fā)度液、調(diào)試厕宗、工具設(shè)計(jì)開發(fā)、數(shù)據(jù)分析恨诱、檢測和驗(yàn)證工作集中式的進(jìn)行媳瞪,對(duì)體力和腦力都是極大的挑戰(zhàn),且壓力巨大照宝。
第一篇記錄了前期的策劃內(nèi)容以及一些提效工具的開發(fā)過程。對(duì)這三周干的事情進(jìn)行了沉淀句葵,沉淀的是一次獨(dú)特的成功經(jīng)驗(yàn)。第二篇是在一年后寫的,更多的是記錄了這一年我對(duì)啟動(dòng)這件事情的思考曼氛,一年時(shí)間的經(jīng)歷也很多喉前,還主負(fù)責(zé)過包體積的項(xiàng)目,所以內(nèi)容就顯得更加豐富了些轻专,有記錄些對(duì)性能和調(diào)試工具的研究忆矛。
第二篇文章里我提到我發(fā)現(xiàn)了一個(gè)寶藏男孩Michael Eisel,發(fā)現(xiàn)了很多二手資料都是源自他的博客请垛。另外由于這一年也發(fā)現(xiàn)了性能防劣化中催训,自動(dòng)化分析工具和能力相關(guān)技術(shù)了解的不夠深入。于是專門去探索了下這方面的情況宗收。對(duì)于目前為了保持雙端一直 libimobiledevice漫拭,我發(fā)現(xiàn)了 Facebook 專門針對(duì)蘋果系統(tǒng)開發(fā)的 idb,idb 做法明顯更聰明些混稽。
這些探究的過程至少是獨(dú)特的采驻。更獨(dú)特的地方是文中寫的那個(gè)A庫多線程問題的排查經(jīng)歷审胚。痛苦的經(jīng)歷我已在文中清晰詳細(xì)的記錄了,歷時(shí)三天三夜礼旅,當(dāng)大家試完所有情況膳叨,士氣全無時(shí),才柳暗花明又一村痘系。全因蘋果的一個(gè) bug懒鉴。經(jīng)歷這么一遭,對(duì)于 GCD 的隊(duì)列排查定位問題難這點(diǎn)碎浇,我看國外對(duì) iOS 并發(fā)開發(fā)方式吐槽的聲音也很大临谱,于是我很想了解多線程問題蘋果未來會(huì)怎么處理。這就有了文中 Swift 并發(fā)提案部分的分析奴璃。當(dāng)時(shí)這份提案還未進(jìn)入正式流程(現(xiàn)在已經(jīng)在 Swift 5.5正式發(fā)布了)悉默,未來并不明朗,我也擔(dān)心會(huì)遺漏關(guān)鍵信息苟穆,于是對(duì)涉及相關(guān)的提案都進(jìn)行了閱讀抄课,包括那些提案下所有的評(píng)論也都看了。
這兩篇文章跨越了整整一年時(shí)間雳旅,這一年期間我基本沒有寫其他的文章跟磨,但是卻沉淀了很多,所以第二篇實(shí)際上可寫的內(nèi)容非常多攒盈,一口氣挑著重點(diǎn)的說了一大篇后抵拘,還刪減了大量內(nèi)容。寫完第二篇我感覺到化繁為簡的巨大好處型豁。自己做的記錄僵蛛、素材和資料往往都是大量的,深究下去都是無窮無盡的感覺迎变。因此需要從中提煉出自己的觀點(diǎn)充尉。從那么多內(nèi)容中提煉出觀點(diǎn)是需要足夠的休息和放松,讓你的潛意識(shí)主動(dòng)來幫助你衣形。這些休息和放松也可以是在日常的行為中驼侠,比如洗澡、去超市買東西谆吴、騎自行車倒源、走路、鍛煉纪铺、吃飯和睡覺等相速,特別是走路和睡覺持續(xù)時(shí)間長,最容易進(jìn)入深度思考鲜锚。不斷給自己提問題進(jìn)而更大量的閱讀找答案突诬,思考內(nèi)在邏輯和聯(lián)系苫拍。發(fā)散的找,專注的收斂提取觀點(diǎn)旺隙,這樣的觀點(diǎn)是用錢買不到的绒极。
通過大白話講清楚,分享出去蔬捷,這樣的觀點(diǎn)在他人接收時(shí)是自然地垄提,意識(shí)不到其背后所花的時(shí)間和功夫,這就跟優(yōu)秀的 App 一樣周拐,用起來是那么簡單有效铡俐,絲毫不拖泥帶水,用戶也意識(shí)不到開發(fā) App 所付出的腦動(dòng)妥粟。這種化繁為簡的過程也是將無序雜亂的東西清理掉审丘,讓你寶貴精煉的思想能夠有地方存放。
灌籃高手中流川楓打籃球行云流水勾给,天賦異稟滩报。背后的努力誰又能知曉。我印象最深的一段是櫻木花道為了取得晴子芳心播急,但始終技不如流川楓脓钾,總以為是天賦不夠。一天晚上櫻木花道很晚來到籃球館桩警,發(fā)現(xiàn)流川楓還在苦練可训,才發(fā)現(xiàn)原來白天看起來懶散傲慢的流川楓原來比誰都要刻苦,簡單輕松從來都不是廉價(jià)的生真。
對(duì)于分享沉噩,有智慧的人都懂得給予越多收獲越大。友情比金錢價(jià)值更高柱蟀,就好像有一個(gè)開電影公司的朋友比擁有一家電影公司要好。分享不是要得到他人的認(rèn)可蚜厉,如果你知道這點(diǎn)长已,你擁有的能量就是無窮的,力量也是無敵的昼牛。
沒怎么寫過术瓮,那下一步怎么行動(dòng)
看到這里,你一定會(huì)想“看你說了那么多贰健,但我雙手放在鍵盤前胞四,腦袋還是一片空白,無從下手”伶椿。
如果想幫其他人辜伟,讓他真的動(dòng)手去做些什么事情氓侧,其實(shí)更應(yīng)該是要讓做這件事情變得容易很多倍,但方向是一樣的导狡,這樣下次他就更好接受些约巷。互聯(lián)網(wǎng)開始發(fā)布內(nèi)容門檻高旱捧,后來有了微博和朋友圈這種能夠一句話就快速發(fā)布出去的產(chǎn)品后独郎,大家發(fā)內(nèi)容就比以前更多了。去讀資料和文章枚赡,可以懂更多的知識(shí)氓癌,自身能力還是需要通過練習(xí)才能夠有提升。想把事情做好贫橙,還是需要去做贪婉。
因此你應(yīng)該更重視動(dòng)手寫,如果你不知道如何寫料皇,可能就不知道如何思考谓松。有叛逆和逆向思維的人常常是愛問問題的人,愛自問愛思考践剂,對(duì)那些已經(jīng)共識(shí)正在運(yùn)作的事物提出疑問鬼譬,尋找和關(guān)注答案,這樣才會(huì)有打破現(xiàn)狀的意識(shí)逊脯。一些人小時(shí)候就能看到有這樣的特點(diǎn)优质,因此在別人教你怎樣怎樣做時(shí),不要太當(dāng)回事军洼,相信自己實(shí)踐出來的答案巩螃。多聽你喜歡人說話,多傾聽匕争,不斷問還有沒想說的避乏。
還要從各種類型人那學(xué)習(xí),甚至是和你觀點(diǎn)不同的人甘桑。因?yàn)樵诿總€(gè)人堅(jiān)持的思想里拍皮,都會(huì)有他自己獨(dú)特的經(jīng)歷和實(shí)踐總結(jié)來的結(jié)論。通過他們的結(jié)論跑杭,你也可以自己去實(shí)踐和驗(yàn)證形成自己的觀點(diǎn)铆帽,這樣就會(huì)有復(fù)利效應(yīng)。做的結(jié)果其實(shí)并不重要德谅,重要的是在做的過程中爹橱,你自己有沒有變得更好。
你說的話窄做,你的觀點(diǎn)愧驱,你的評(píng)論都不能代表你慰技,而是你所做的事情,花了很多時(shí)間做的事情那才是你冯键。改變一個(gè)人的行為來改變思維惹盼,比改變一個(gè)人的思維來改變行為要容易的多很多。
因此惫确,光看光聽不動(dòng)手寫是沒用的手报。那行動(dòng)起來的話,怎么做更好些呢改化?
四個(gè)步驟
第一步掩蛤,零散的想法、工作內(nèi)容和看到的好的技術(shù)資料及時(shí)記錄陈肛,先按照時(shí)間軸的方式記錄揍鸟。這一步是很容易操作的,幾乎不用費(fèi)腦句旱,只需要機(jī)械的做記錄就行阳藻,也不用考慮先前提到四個(gè)點(diǎn)里任何一個(gè)。
第二步谈撒,對(duì)于記錄的內(nèi)容進(jìn)行分類腥泥,開始粒度可以粗一點(diǎn),比如性能啃匿、架構(gòu)蛔外、構(gòu)建、編程語言溯乒、管理夹厌、成長、旅行和科技等裆悄,根據(jù)自身興趣點(diǎn)和期望發(fā)展方向來就好矛纹。
第三步,做完一個(gè)項(xiàng)目光稼,或者想對(duì)先前做的事情進(jìn)行總結(jié)時(shí)崖技,先一口氣快速寫出想表達(dá)的內(nèi)容出來,這時(shí)寫的內(nèi)容體現(xiàn)出獨(dú)特性钟哥,搭好骨架。然后針對(duì)寫的內(nèi)容中的一些技術(shù)點(diǎn)瞎访,進(jìn)行真實(shí)感的完善腻贰。真實(shí)感的完善是需要很多素材和資料的,這時(shí)在第一步和第二步做的工作和積累就能夠派上用場了扒秸。找到相關(guān)大分類進(jìn)行細(xì)分來補(bǔ)充文章的血肉播演。
第四步冀瓦,也是最后一步,可以充分發(fā)揮自己軟實(shí)力和創(chuàng)造力写烤,通過故事性和新意來披上文章的皮膚翼闽,讓文章能夠看起來更加完整和吸引人,提高閱讀的體驗(yàn)洲炊。
完整完成這四個(gè)步驟并不容易感局,經(jīng)常就會(huì)因?yàn)槎栊园胪径鴱U。這時(shí)就需要 push 自己一把暂衡,方法的話询微,我這邊的經(jīng)驗(yàn)就是定目標(biāo),定時(shí)間節(jié)點(diǎn)狂巢。比如定好一個(gè)對(duì)外分享的時(shí)間撑毛,這樣目標(biāo)性更強(qiáng),同時(shí)也有了約束和責(zé)任唧领,自己的惰性在這一段時(shí)間內(nèi)就能夠得到很好的消減藻雌。
為了達(dá)成目的,徹底理清你想要啥斩个,還需要清空干擾胯杭,方法很簡單,除了當(dāng)前最重要的事情萨驶,其它所有待做事情都記在備忘錄里以便追蹤防止遺漏歉摧。完成當(dāng)前事情后,再去查看備忘錄腔呜,然后定新目標(biāo)新計(jì)劃叁温。
完成文章后可以通過下面八個(gè)問題來檢查下文章的完成度。
- 我為什么做這件事核畴?
- 誰已經(jīng)做了膝但?他們都是怎么做的?效果怎樣谤草?
- 我和他們做的不一樣在哪跟束?怎么想到的?能詳細(xì)具體說出涉及相關(guān)知識(shí)點(diǎn)嗎丑孩?(??重點(diǎn)冀宴,寫好了的話,其他問題可有可無)
- 我碰到了什么困難温学?
- 我怎么解決的略贮?
- 做的有亮點(diǎn)嗎?為什么是亮點(diǎn)?
- 做完后效果是怎樣的逃延?超預(yù)期地方在哪览妖?
- 以后還有計(jì)劃打算嗎?為什么揽祥?
所用軟件
下面是我寫文章會(huì)用到的一些軟件讽膏,以及我關(guān)注和用到的一些特性:
系統(tǒng)自帶備忘錄
- 零散想法和靈感記錄
- 待做事項(xiàng)記錄(一個(gè)一個(gè)直接刪掉的感覺不錯(cuò))
- 聚焦想法思路,不用去考慮分類整理等
- 本地文檔管理(多設(shè)備同步收費(fèi))
- 標(biāo)簽系統(tǒng)簡化分類
- 在線文檔管理
- 數(shù)據(jù)庫方式管理拄丰,分類府树、檢索和排序
- 字段自定義添加,比如標(biāo)簽愈案、類別挺尾、鏈接、標(biāo)題等等都可以自定義
- 基于數(shù)據(jù)庫和自定義字段可生成看板站绪、時(shí)間軸遭铺、日歷、列表恢准、表格魂挂、網(wǎng)格等不同視圖樣式查看。
- 有chrome插件
- 本地文檔管理(文件夾馁筐,Git支持可多端同步)
- Markdown 插件支持(Markdown All in One涂召、Pangu-Markdown、Markdown Preview Enhanced敏沉、Word Count CJK)
- 本地文檔管理(文件夾)
- Markdown原生支持
- 插件系統(tǒng)果正,比如有大綱和看板等插件可用
- 雙向鏈接與關(guān)系圖譜
- 可以把在紙上的草圖配上顏色
軟件使用上,我會(huì)通過備忘錄或熊掌記快速記錄一些素材和想法盟迟,定期挪到 Notion 里秋泳,我是把 Notion 當(dāng)做一個(gè)大倉庫,寫作的第二階段整理分類我就是在 Notion 中完成的攒菠,充分利用 Notion 的自定義字段能力迫皱,對(duì)所有資料進(jìn)行各種維度劃分和歸檔。開始寫文章時(shí)辖众,初期會(huì)用 VS Code 來寫卓起,如果文章寫長了就會(huì)打開 Obsidian 來繼續(xù)寫,主要是 Obsidian 的大綱效果比較好些凹炸。最后文章的配圖我會(huì)使用 Procreate 來畫戏阅,里面有輔助線,打開后可以很方便做參照啤它,寫圖中文字就不容易偏了饲握。
工具只是工具私杜,記錄的內(nèi)容和自己的思想才是核心。我現(xiàn)在讀書還是喜歡在紙上寫筆記救欧,特別有感觸的才會(huì)提煉一些觀點(diǎn)敲到備忘錄中,比如我看了網(wǎng)飛(Nexflix)的《不拘一格》后提煉了一些觀點(diǎn)做了記錄锣光,筆記如下:
制度都是圍繞著怎么不阻礙所要的人發(fā)揮笆怠。比如假期自由安排、無審批誊爹、決策權(quán)非自上而下蹬刷,而是在認(rèn)識(shí)一致情況下松散耦合。
要和不要什么樣的人呢频丘?
不要的人:
與人相處好办成,但能力平平
工作狂,缺少判斷力
天資好搂漠,行動(dòng)力強(qiáng)迂卢,但悲觀、牢騷
有才華的混蛋:
特征
聽到贊美就自覺優(yōu)秀
對(duì)想法不明智的人桐汤,會(huì)進(jìn)行嘲笑
會(huì)侮辱天賦不如自己的人
表現(xiàn)
喜歡會(huì)上慷慨陳詞而克,重復(fù)表達(dá)自己觀點(diǎn)
如沒抓住他的要點(diǎn),會(huì)打斷別人的話
別人發(fā)言怔毛,不贊同時(shí)會(huì)不聽员萍,做自己的事情
別人啰嗦,沒抓住要點(diǎn)拣度,立刻打斷
總想著怎么做才能表現(xiàn)好碎绎,得獎(jiǎng)金,缺少開放的認(rèn)知空間
為什么:管理花費(fèi)精力多抗果,討論質(zhì)量低筋帖,會(huì)排擠卓越員工。
要的人:
非凡創(chuàng)造力窖张、工作出色(完成繁重任務(wù))幕随、合作好
在放松狀態(tài)下,會(huì)靈光乍現(xiàn)
公司利益至上
自覺追求成功宿接,無論是否有獎(jiǎng)金(已給予能力匹配市場最高價(jià))
當(dāng)某一固定思維遇到瓶頸時(shí)赘淮,他總有辦法擺脫瓶頸,或嘗試不同角度看待問題
在有才能睦霎,受愛戴的前提下梢卸,自己犯錯(cuò)大聲說,成功小聲說副女,讓人感覺親近蛤高、真誠和體貼。
有良好的判斷力
為什么:優(yōu)秀的人激勵(lì)其他優(yōu)秀的人,出色成果感染更多人才戴陡。
只有公司里的員工都是上面提到的要的人時(shí)塞绿,公司的密度才高。這樣的公司不是家庭而是專業(yè)運(yùn)動(dòng)隊(duì)恤批,運(yùn)動(dòng)隊(duì)追求卓越异吻,每個(gè)位置都是最佳人選;訓(xùn)練就是為了勝利喜庞,大家都能給予和接受反饋诀浪;成績要好,不能只用努力就夠了延都。
書中詳細(xì)介紹了網(wǎng)飛的制度由來雷猪,大量員工的實(shí)際案例,碰到了問題如何完善了制度晰房。非常全面進(jìn)行了制度介紹求摇,甚至包含了進(jìn)行創(chuàng)新的幾個(gè)步驟的詳細(xì)說明,還有網(wǎng)飛創(chuàng)始人里德是如何做到讓大家認(rèn)識(shí)一致的嫉你。
最后是書中引用的小王子那段:
如果你想造艘船月帝,
不要老催人去采木,
忙著分配工作
和發(fā)號(hào)施令幽污。
而是要激起他們
對(duì)浩瀚無垠的
大海的向往嚷辅。
舉個(gè)例子,怎么寫這次WWDC21的見聞文章
光說不練距误,這樣不好吧簸搞,那就現(xiàn)舉個(gè)例子,看看怎么按照上面的四個(gè)步驟一步一步寫一篇技術(shù)文章准潭。那就以現(xiàn)在剛開完的 WWDC21 為主題趁俊,寫個(gè)《WWDC21我的見聞》吧。
首先我們先做第一步,從 WWDC21 開始,我就將我看到的信息憎亚、還有看感興趣 Session 中有用的點(diǎn)都記錄了下來唯笙,只考慮是否要記黔宛,二不考慮其它任何事情。你可以看我WWDC21第一天的記錄,我將其發(fā)到了我的博客和公眾號(hào)上。后面幾天我也不斷的收集記錄著零碎的信息挡逼。然后對(duì)這些記錄進(jìn)行分類。接下來再開始內(nèi)容的撰寫腻豌。
寫 WWDC21 見聞錄家坎,你可以先想想著你想要什么內(nèi)容嘱能,有沒人提供,有的話可以直接鏈過來虱疏,沒有的話可以自己去體會(huì)惹骂,去想,去經(jīng)歷订框,然后分享出來析苫。
我會(huì)先寫個(gè)總覽,內(nèi)容如下穿扳。
總覽
WWDC21 官方通過一個(gè)頁面匯總了發(fā)布的新技術(shù),詳見這里国旷。WWDC21 里的代碼范例官方都有提供和匯總矛物,詳見這里。WWDC21 期間蘋果也列出了蘋果公司之外圍繞 WWDC 其它組織的學(xué)習(xí)跪但、交流和娛樂的活動(dòng)履羞。
如果沒有太多時(shí)間看 Session 視頻,也可以直接看其他人的筆記屡久,國外有WWDC NOTES忆首,國內(nèi)有老司機(jī)技術(shù)周刊的WWDC21 內(nèi)參。往屆內(nèi)容也有人做了匯總
簡單筆記可以查缺補(bǔ)漏被环,Alejandro Martinez 在這篇文章WWDC21 notes中對(duì)各種主題做了簡單的記錄糙及,列出了關(guān)鍵字方便檢索。
Session推薦
全部 Session筛欢,在這里查看浸锨。這里有份推薦清單。我也列了下我關(guān)注的 Session版姑。如下:
SwiftUI 相關(guān) Session:
- What's new in SwiftUI:包括了所有SwiftUI這次的更新內(nèi)容介紹柱搜。
- Add rich graphics to your SwiftUI app:內(nèi)容包括安全區(qū)域、材質(zhì)包剥险、畫布API等聪蘸。
- Craft search experiences in SwiftUI:.searchable修飾符的使用。
- Direct and reflect focus in SwiftUI:關(guān)于移動(dòng)焦點(diǎn)的使用表制。
- SwiftUI on the Mac: Build the fundamentals:內(nèi)容是一步一步構(gòu)建一個(gè)macOS應(yīng)用健爬。
- SwiftUI on the Mac: The finishing touches:展示如何通過設(shè)置讓人們靈活定制一個(gè)應(yīng)用程序。
- Demystify SwiftUI:介紹了SwiftUI的三個(gè)核心Identity夫凸、Lifetime和Dependencies浑劳。
- Discover concurrency in SwiftUI:展示并發(fā)工作流如何和SwiftUI數(shù)據(jù)流進(jìn)行結(jié)合。
- SF Symbols in SwiftUI:定義Symbols的大小夭拌,顯示不同變體以及Symbols著色魔熏。
Swift Concurrency 相關(guān) Session:
- Meet async/await in Swift:了解 async/await 開發(fā)模式衷咽。
- Explore structured concurrency in Swift:內(nèi)容包括創(chuàng)建不同類型并發(fā)任務(wù),如何創(chuàng)建任務(wù)組蒜绽,如何取消正在進(jìn)行的任務(wù)镶骗。
- Protect mutable state with Swift actors:內(nèi)容有如何使用Swift actors組織資源競爭,actors如何工作等躲雅。
- Swift concurrency: Behind the scenes:了解更多Swift并發(fā)的細(xì)節(jié)鼎姊,更安全的數(shù)據(jù)競爭和處理線程爆炸,和GCD的不同相赁,線程模型怎么工作等相寇。值得看多遍。
- Swift concurrency: Update a sample app:介紹async/await钮科、actors和continuation在現(xiàn)實(shí)工作中的經(jīng)驗(yàn)
- Meet AsyncSequence:流式傳輸數(shù)據(jù)唤衫。
- Use async/await with URLSession:URLSession中怎么使用async/await和AsyncSequence。
DocC:
- Meet DocC documentation in Xcode:了解如何使用DocC绵脯,如何生成DocC檔案佳励,并讓他們顯示在文檔瀏覽器中。
- Host and automate your DocC documentation:如何通過自己的服務(wù)器托管DocC蛆挫,自動(dòng)構(gòu)建和分發(fā)DocC檔案赃承。
- Elevate your DocC documentation in Xcode:介紹寫文檔的最佳實(shí)踐。
- Build interactive tutorials using DocC:編寫交互教程悴侵。
其它感興趣的 Session:
- Write a DSL in Swift using result builders:使用 result builders 來創(chuàng)建DSL瞧剖,是代碼更容易閱讀和維護(hù)。
- Create 3D models with Object Capture:捕獲現(xiàn)實(shí)對(duì)象畜挨,生成3D模型筒繁。
- What’s new in SF Symbols:SF Symbols的更新。介紹如何讓自定義符號(hào)支持單色巴元、分層毡咏、調(diào)色板和多色渲染模式。
- Explore the SF Symbols 3 app:SF Symbols應(yīng)用程序的更新逮刨。
- Create custom symbols:創(chuàng)建自定義symbols呕缭。
- Ultimate application performance survival guide:關(guān)于性能優(yōu)化的話題,內(nèi)容包括性能相關(guān)工具修己、指標(biāo)和范式恢总。會(huì)涉及到Instruments、XCTest睬愤、MetricKit等等技術(shù)和工具片仿。iOS 15的動(dòng)態(tài)鏈接器做了優(yōu)化能夠啟動(dòng)提速并減少Swift二進(jìn)制大小∮热瑁可以參看這篇文章
- Symbolication: Beyond the basics:介紹符號(hào)化的過程砂豌。
- Meet the Swift Algorithms and Collections packages:講的通俗易懂厢岂。
Swift 的一些更新
Paul Hudson 的這篇What's new in Swift 5.5? 已經(jīng)把這些更新說的非常詳細(xì)了,每個(gè)更新點(diǎn)都有對(duì)應(yīng)的例子可以試阳距。今年蘋果公司推出 AttributedString 用來替代 OC 時(shí)代的 NSAttributedString塔粒。AttributedString 是值類型,可以直接在 SwiftUI 的 Text 里使用筐摘。AttributedString 還支持簡單的 Markdown 語法卒茬,Markdown 單行沒問題,多行功能受限咖熟。
DocC 是通過 Xcode 編譯后生成的文檔圃酵,使用 Product -> Build Documentation 就會(huì)生成DocC。在函數(shù)接口代碼上使用 Shift+Cmd+A 快捷鍵就會(huì)創(chuàng)建文檔模板馍管,有參數(shù)和返回值的話也會(huì)將其提取出來辜昵,包括參數(shù)類型等,并生成標(biāo)準(zhǔn)文檔格式咽斧,方便你進(jìn)行內(nèi)容編寫」妫基本 Markdown 語法是支持的张惹。詳細(xì)的介紹可以看前面列出的官方 Session,或者看這篇文章How to document your project with DocC岭洲。
今年重頭戲 Swift Concurrency
ABI 穩(wěn)定后宛逗,Swift 的核心團(tuán)隊(duì)可以開始關(guān)注 Swift 語言一直缺失的原生并發(fā)能力了。最初是由Chris Lattner在17年發(fā)的Swift并發(fā)宣言盾剩,從此開闊了大家的眼界雷激。后來 Swift Evolution 社區(qū)討論了十幾個(gè)提案,幾十個(gè)方案告私,以及幾百頁的設(shè)計(jì)文件屎暇,做了大量的改進(jìn),社區(qū)中用戶積極的參與反饋驻粟,Chris 也一直在 Evolution 中積極的參與設(shè)計(jì)根悼。
Swift Concurrency 的實(shí)現(xiàn)用了LLVM的協(xié)程把 async/await 函數(shù)轉(zhuǎn)換為基于回調(diào)的代碼,這個(gè)過程發(fā)生在編譯后期蜀撑,這個(gè)階段你的代碼都沒法辨識(shí)了挤巡。異步的函數(shù)被實(shí)現(xiàn)為 coroutines,在每次異步調(diào)用時(shí)酷麦,函數(shù)被分割成可調(diào)用的函數(shù)部分和后面恢復(fù)的部分矿卑。coroutine 拆分的過程發(fā)生在生成LLVM IR階段。Swift使用了哪些帶有自定義調(diào)用約定的函數(shù)保證尾部調(diào)用沃饶,并專門為Swift進(jìn)行了調(diào)整母廷。
Swift Concurrency 不是建立在 GCD 上轻黑,而是使用的一個(gè)全新的線程池。GCD 中啟動(dòng)隊(duì)列工作會(huì)很快在提起線程徘意,一個(gè)隊(duì)列阻塞了線程苔悦,就會(huì)生成一個(gè)新線程∽颠郑基于這種機(jī)制 GCD 線程數(shù)很容易比 CPU 核心數(shù)量多玖详,線程多了,線程就會(huì)有大量的調(diào)度開銷勤讽,大量的上下文切換蟋座,會(huì)使 CPU 運(yùn)行效率降低。而 Swift Concurrency 的線程數(shù)量不會(huì)超過 CPU 內(nèi)核脚牍,將上下文切換放到同一個(gè)線程中去做向臀。為了實(shí)現(xiàn)線程不被阻塞,需要通過語言特性來做诸狭。做法是券膀,每個(gè)線程都有一個(gè)堆棧記錄函數(shù)調(diào)用情況,一個(gè)函數(shù)占一個(gè)幀驯遇。函數(shù)返回后芹彬,這個(gè)函數(shù)所占的幀就會(huì)從堆棧彈出。await 的 async 函數(shù)被作為異步幀保存在堆上等待恢復(fù)叉庐,而不阻礙其它函數(shù)入棧執(zhí)行舒帮。在 await 后運(yùn)行的代碼叫 continuation,continuation 會(huì)在要恢復(fù)時(shí)放回到線程的堆棧里陡叠。異步幀會(huì)根據(jù)需要放回棧上玩郊。在一個(gè)異步函數(shù)中調(diào)用同步代碼將添加幀到線程的堆棧中。這樣線程就能夠一直向前跑枉阵,而不用創(chuàng)建更多線程減少調(diào)度译红。
Douglas 在 Swift 論壇里發(fā)的 Swift Concurrency 下個(gè)版本的規(guī)劃貼 Concurrency in Swift 5 and 6,論壇里還有一個(gè)帖子是專門用來征集Swift Concurrency意見的岭妖,帖子本身列出了 Swift Concurrency 相關(guān)的所有提案临庇,也提出歡迎有新提案發(fā)出來,除了這些提案可以看外昵慌,帖子回復(fù)目前已經(jīng)過百假夺,非常熱鬧,可以看出大家對(duì) Swift Concurrency 的關(guān)注度相當(dāng)?shù)母摺?/p>
非常多的人參與了 Swift Concurrency 才使其看起來和用起來那么簡單斋攀。Doug Gregor 在參與 John Sundell 的播客后已卷,發(fā)了很多條推聊 Swift Concurrency,可以看到參與的人非常多淳蔼,可見背后付出的努力有多大侧蘸。下面我匯總了 Doug Gregor 在推上發(fā)的一些信息裁眯,你通過這些信息也可以了解 Swift Concurrency 幕后信息,所做的事和負(fù)責(zé)的人讳癌。
@pathofshrines是 Swift Concurrency 整體架構(gòu)師穿稳,包括低級(jí)別運(yùn)行時(shí)和編譯器相關(guān)細(xì)節(jié)。@illian是 async sequences晌坤、stream 和 Fundation 的負(fù)責(zé)人逢艘。@optshiftk對(duì) UI 和并發(fā)交互的極好的洞察力帶來了很棒的 async 接口,@phausler帶來了 async sequences骤菠。Arnold Schwaighofer它改、@neightchan、@typesanitizer還有 Tim Northover 實(shí)現(xiàn)了 async calling convention商乎。
@ktosopl有很深厚的 actor央拖、分布式計(jì)算和 Swift-on-Server 經(jīng)驗(yàn),帶來了 actor 系統(tǒng)鹉戚。Erik Eckstein 為 async 函數(shù)和actors建立了關(guān)鍵的優(yōu)化和功能鲜戒。
SwiftUI是@ricketson_和@luka_bernardi完成的async接口。async I/O的接口是@Catfish_Man完成的抹凳。@slava_pestov處理了 Swift 泛型問題袍啡,還指導(dǎo)其他人編譯器實(shí)現(xiàn)的細(xì)節(jié)。async 重構(gòu)工具是Ben Barham 做的却桶。大量代碼移植到 async 是由@AirspeedSwift領(lǐng)導(dǎo),由 Angela Laar蔗牡,Clack Cole颖系,Nicole Jacques 和@mishaldshah共同完成的。
@lorentey負(fù)責(zé) Swift 接口的改進(jìn)辩越。@jckarter有著敏銳的語言設(shè)計(jì)洞察力嘁扼,帶來了語言設(shè)計(jì)經(jīng)驗(yàn)和編譯器及運(yùn)行時(shí)實(shí)現(xiàn)技能。@mikeash 也參與了運(yùn)行時(shí)開發(fā)中黔攒。操作系統(tǒng)的集成是@rokhinip完成的趁啸,@chimz提供了關(guān)于 Dispatch 和 OS 很好的建議,Pavel Yaskevich 和
@hollyborla進(jìn)行了并發(fā)所需要關(guān)鍵類型檢查器的改進(jìn)督惰。@kastiglione不傅、Adrian Prantl和@fred_riss實(shí)現(xiàn)了調(diào)試。@etcwilde和@call1cc實(shí)現(xiàn)了語義模型中的重要部分赏胚。
@evonox負(fù)責(zé)了服務(wù)器Linux 的支持访娶。@compnerd將 Swift Concurrency 移植到了 Windows。
Swift Concurrency 模型簡單觉阅,細(xì)節(jié)都被隱藏了崖疤,比 Kotlin 和 C++的 Coroutine 接口要簡潔很多秘车。比如 Task 接口形式就很簡潔。Swift Concurrency 大體可分為 async/await劫哼、Async Sequences叮趴、結(jié)構(gòu)化并發(fā)和 Actors。下面展開說下眯亦。
async/await
通過類似 throws 語法的 async 來指定函數(shù)為異步函數(shù),異步函數(shù)才能夠使用 await豪嚎,使用異步函數(shù)要用 await搔驼。await 修飾在 suspension point 時(shí)當(dāng)前線程可以讓給其它任務(wù)執(zhí)行,而不用阻塞當(dāng)前線程侈询,等 await 后面的函數(shù)執(zhí)行完成再回來繼續(xù)執(zhí)行舌涨,這里需要注意的是回來執(zhí)行不一定是在離開時(shí)的線程上。async/await 提案是SE-0296扔字。如果想把現(xiàn)有的異步開發(fā)帶到 async/await 世界囊嘉,請(qǐng)使用 withCheckedThrowingContinuation。
async/await 還有一個(gè)非常明顯的好處革为,就是不會(huì)再有[weak self] dance 了扭粱。
Async Sequences
AsyncSequence 的使用方式是 for-await-in 和 for-try-await-in,系統(tǒng)提供了一些接口震檩,如下:
- FileHandle.standardInput.bytes.lines
- URL.lines
- URLSession.shared.data(from: URL)
- let (localURL, _ ) = try await session.download(from: url) 下載和get請(qǐng)求數(shù)據(jù)區(qū)別是需要邊請(qǐng)求邊存儲(chǔ)數(shù)據(jù)以減少內(nèi)存占用
- let (responseData, response) = try await session.upload(for: request, from: data)
- URLSession.shared.bytes(from: URL)
- NotificationCenter.default.notifications
結(jié)構(gòu)化并發(fā)
使用這些接口可以一邊接收數(shù)據(jù)一邊進(jìn)行顯示琢蛤,AsyncSequence 的提案是SE-0298(Swift 5.5可用)。AsyncStream 是創(chuàng)建自己異步序列的最簡單的方法抛虏,處理迭代博其、取消和緩沖。AsyncStream 正在路上迂猴,提案是SE-0314慕淡。
Task 為一組并發(fā)任務(wù)創(chuàng)建一個(gè)運(yùn)行環(huán)境,async let 可以讓任務(wù)并發(fā)執(zhí)行沸毁,結(jié)構(gòu)化并發(fā)(Structured concurrency峰髓,提案在路上SE-0304)withTaskGroup 中 group.async 可以將并發(fā)任務(wù)進(jìn)行分組。
Actors
我們寫的程序會(huì)在進(jìn)程中被拆成一個(gè)一個(gè)小指令息尺,這些指令會(huì)在某刻會(huì)一個(gè)接一個(gè)同步的或者并發(fā)的執(zhí)行携兵。系統(tǒng)會(huì)用多個(gè)線程執(zhí)行并行的任務(wù),執(zhí)行順序是調(diào)度器來管理的搂誉,現(xiàn)代多核可以同時(shí)處理多個(gè)線程眉孩,當(dāng)一個(gè)資源在多個(gè)線程上同時(shí)被更改時(shí)就會(huì)出問題。并發(fā)任務(wù)對(duì)數(shù)據(jù)資源操作容易造成數(shù)據(jù)競爭,以前需要手動(dòng)放到串行隊(duì)列浪汪、使用鎖巴柿、調(diào)度屏障或 Atomics 的方式來避免。以前處理容易導(dǎo)致昂貴的上下文切換死遭,過多線程容易導(dǎo)致線程爆炸广恢,容易意外阻斷線程導(dǎo)致后面代碼沒法執(zhí)行,多任務(wù)相互的等待造成了死鎖呀潭,block 和內(nèi)存引用容易出錯(cuò)等等問題钉迷。
現(xiàn)在 Swift Concurrency 可以通過 actor 來創(chuàng)建一個(gè)區(qū)域,在這個(gè)區(qū)域會(huì)自動(dòng)進(jìn)行數(shù)據(jù)安全保護(hù)钠署,保證一定時(shí)間只有一個(gè)線程訪問里面數(shù)據(jù)糠聪,防止數(shù)據(jù)競爭。actor 內(nèi)部對(duì)成員訪問是同步的谐鼎,成員默認(rèn)是隔離的舰蟆,actor 外部對(duì) actor 內(nèi)成員的訪問只能是異步的,隱式同步以防止數(shù)據(jù)競爭狸棍。MainActor 繼承自能確保全局唯一實(shí)例的 GlobalActor身害,保證任務(wù)在主線程執(zhí)行,這樣你就可以拋棄掉在你的 ViewModel 里寫 DispatchQueue.main.async 了草戈。
Actors 的概念通常被用于分布式計(jì)算塌鸯,Actor 模型參看Wikipedia里的詳細(xì)解釋,Swift 中的實(shí)現(xiàn)效果也非常的理想唐片。Actors 的提案SE-0306已在 Swift 5.5落實(shí)丙猬。
很多語言都支持 actors 還有 async/await,實(shí)現(xiàn)的方式也類似费韭,actor 使用的不是鎖淮悼,而是用的 async/await 這樣能夠在一個(gè)線程中切換上下文來避免線程空閑的線程模型。actor 還利用編譯器揽思,提前做會(huì)引起并發(fā)問題的檢查。
actor 是遵循 Sendable 協(xié)議的见擦,只有結(jié)構(gòu)體和 final 類才能夠遵循 Sendable钉汗,繼承于 Sendable 協(xié)議的 Excutor 協(xié)議表示方法本身,SerialExecutor 表示以串行方式執(zhí)行鲤屡。actor 使用 C++寫的损痰,源碼在這里,可以看到 actor 主要是通過控制各個(gè) job 執(zhí)行的狀態(tài)的管理器酒来。job 執(zhí)行優(yōu)先級(jí)來自 Task 對(duì)象卢未,排隊(duì)時(shí)需要確保高優(yōu) job 先被執(zhí)行。全局 Executor 用來為 job 排隊(duì),通知 actor 擁有或者放棄線程辽社,實(shí)現(xiàn)在這里伟墙。由于等待而放棄當(dāng)前線程讓其他 actor 執(zhí)行的 actor,在收到全局 Executor 創(chuàng)建一個(gè)新的 job 的通知滴铅,使其可以進(jìn)入一個(gè)可能不同線程戳葵,這個(gè)過程就是并發(fā)模型中描述的 Actor Reentrancy。
Swift Concurrency相關(guān)提案集合
所有相關(guān)提案清單如下:
- SE-0296: Async/await 【譯】SE-0296 Async/await
- SE-0317: async let
- SE-0300: Continuations for interfacing async tasks with synchronous code 【譯】SE-0300 Continuation -- 執(zhí)行同步代碼的異步任務(wù)接口
- SE-0302: Sendable and @Sendable closures
- SE-0298: Async/Await: Sequences 【譯】SE-0298 Async/Await 序列
- SE-0304: Structured concurrency
- SE-0306: Actors 【譯】SE-0306 Actors
- SE-0313: Improved control over actor isolation
- SE-0297: Concurrency Interoperability with Objective-C 【譯】SE-0297 Concurrency 與 Objective-C 的交互
- SE-0314: AsyncStream and AsyncThrowingStream
- SE-0316: Global actors
- SE-0310: Effectful read-only properties
- SE-0311: Task Local Values
- Custom Executors
學(xué)習(xí)路徑
如果打算嘗試 Swift Concurrency 的話汉匙,按照先后順序拱烁,可以先看官方手冊介紹文章Concurrency。再看Meet async/await in Swift這個(gè)Session噩翠,了解背后原理看Explore structured concurrency in Swift戏自。動(dòng)手照著試示例代碼,看Paul的Swift Concurrency by Example這個(gè)系列伤锚。接著看Protect mutable state with Swift actors來了解 actors 怎么防止數(shù)據(jù)競爭擅笔。通過Discover concurrency in SwiftUI看 concurrency 如何在 SwiftUI 中使用,Use async/await with URLSession來看怎么在 URLSession 中使用 async/await见芹。最后聽聽負(fù)責(zé) Swift Concurrency 的 Doug Gregor 參加的一個(gè)播客的訪談剂娄,了解下 Swift Concurrency 背后的故事。
Swift Concurrency 和 Combine
由于 Swift Concurrency 的推出和大量的 Session 發(fā)布玄呛,特別是AsyncSequence的出現(xiàn)阅懦,以及正在路上的AsyncStream、AsyncThrowingStream和continuation提案(在Xcode 13.0 beta 3 AsyncStream 正式release)徘铝,這些越來越多和 Combine 功能重疊的特性出現(xiàn)在 Swift Concurrency 藍(lán)圖里時(shí)耳胎,大家開始猜測是否 Combine 會(huì)被 Swift Concurrency 替代。關(guān)于未來是 Swift Concurrency 還是 Combine惕它,我的感覺是怕午,Combine 更側(cè)重在響應(yīng)式編程上,而響應(yīng)式編程并不是所有開發(fā)人員都會(huì)接受的淹魄,而 Swift Concurrency 是所有人都愿意接受的開發(fā)方式郁惜,從 Swift Concurrency 推出后開發(fā)者使用的數(shù)量和社區(qū)反應(yīng)火熱程度來看都比 Combine 要大。在蘋果對(duì) Combine 有下一步動(dòng)作之前甲锡,我還是更偏向 Swift Concurrency兆蕉。
見聞寫到這里,把獨(dú)特性比作骨架缤沦,真實(shí)感比作血肉虎韵,故事性和新意比作皮膚,你會(huì)發(fā)現(xiàn)沒有寫出自己的經(jīng)歷的話缸废,就像進(jìn)擊巨人里的那些小巨人包蓝,即使有了完整的皮膚驶社,但骨頭架子不大是不會(huì)有開頭踢破大門的只有骨架和血肉的巨型大巨人那么強(qiáng)大且震撼有力。
那么接下來我就描寫一些我在 WWDC21 期間獨(dú)特的一些經(jīng)歷测萎。
WWDC.playground直播活動(dòng)
想想 WWDC21 過程中我還是有些經(jīng)歷亡电,比如參加了蘋果官方推薦的外圍活動(dòng)WWDC.playgournd by SwiftGG。
連續(xù)看了5天活動(dòng)直播绳泉,還參加了一天的 Live Coding 介紹 SwiftUI 的新特性逊抡。直播 Live Coding 準(zhǔn)備的時(shí)間很少,而且以前我還沒有現(xiàn)場當(dāng)著幾千人面寫代碼的經(jīng)歷零酪,直播前一天晚上趕著通宵達(dá)旦看完了相關(guān) Session冒嫡,寫了些代碼樣例測試,當(dāng)天白天還開了一個(gè)很長的會(huì)四苇,回家前和同事討論一個(gè)技術(shù)問題時(shí)孝凌,我發(fā)現(xiàn)我嗓子還啞了。到家坐在桌前腳還抽筋了月腋,你可想象到我當(dāng)時(shí)內(nèi)心有多崩潰蟀架。
在直播前,我還專門的給思琦先演練了一遍榆骚,其中在介紹 AsyncImage 處理失敗片拍、空白屿脐、成功還有默認(rèn)情況時(shí)黍析,編譯器報(bào)錯(cuò)提示無法找到原因,還提示讓我提交 bug 的錯(cuò)誤信息互订。直播開始前一直沒有找到原因碉钠,重新敲了一遍才解決纲缓,所以心里沒底,直播開始時(shí)還一直擔(dān)心這個(gè)問題會(huì)重現(xiàn)喊废。直播時(shí)在寫到這段時(shí)果然編譯器錯(cuò)誤又出現(xiàn)了祝高,當(dāng)時(shí)我腦袋一片空白,心中大呼救我污筷。好在沒多一會(huì)我突然發(fā)現(xiàn)先前一段演示的 placeholder 接口沒有刪掉工闺,原因真的就是這個(gè),刪掉后就正常了瓣蛀,別提有多開心了陆蟆。后面就輕松了很多。由于只有一天時(shí)間準(zhǔn)備揪惦,很多內(nèi)容準(zhǔn)備了,當(dāng)時(shí)一邊敲代碼一邊說也漏說了很多罗侯,比如 AsyncImage 使用的是 URLSession器腋,用的是 URLCache,還不能自定義緩存。Refreshable 只能用在 List 里纫塌。SwiftUI 和數(shù)組綁定的代碼是可以兼容前一個(gè)版本的诊县。
另外還有個(gè) WWDC 期間很火的老系統(tǒng)UI挑戰(zhàn)賽讓我印象深刻,其中有個(gè)18歲小伙用 SwiftUI 開發(fā)了經(jīng)典 iPhone4可用版本最火爆措左,Github 地址在這里依痊。
SwitUI 新特性太多了,直播沒提到的還有 task modifier怎披、separator胸嘁、macOS 上的 table、Canvas凉逛、preview in landscape性宏、@FocusState、more button 等等状飞。當(dāng)時(shí)直播有回放毫胜,可以在這里看。更完整詳細(xì)介紹建議看前面提到 SwiftUI 相關(guān) Session诬辈。
WWDC.playgournd 最后一天直播有場 WWDC21 學(xué)生挑戰(zhàn)賽獲獎(jiǎng)?wù)邚堊镶姆窒斫褪梗窒砹嗽鯓訙?zhǔn)備挑戰(zhàn)賽的過程,通過詳細(xì)的過程介紹焙糟,心得體會(huì)口渔,還有思考,讓大家了解到了她的熱情和才華酬荞,而且分享的形式和效果非常有新意搓劫。最后一場的回放看這里』烨桑看完這場后枪向,我打算在19號(hào) SwiftGG 和快手中學(xué)合辦的 WWDC<T> 沙龍活動(dòng)中使用一種不同的方式進(jìn)行分享。原先打算的是使用先前寫好的一個(gè)示例展示使用 SwiftUI 開發(fā)復(fù)雜應(yīng)用如何快捷咧党,同時(shí)介紹背后的技術(shù)秘蛔。幾天想來想去,反復(fù)推敲推翻傍衡,一直沒有新思路深员。最后到了前一天,我有了個(gè)主意蛙埂,可以使用 SwiftUI 來編寫一個(gè)幻燈片程序來分享 SwiftUI 的內(nèi)容啊倦畅,同時(shí)還能夠分享這個(gè)幻燈片開發(fā)過程心得,這樣才有獨(dú)特性和真實(shí)感嘛绣的。于是把準(zhǔn)備了一年的內(nèi)容都刪了叠赐,就像當(dāng)時(shí)啟動(dòng)那篇?jiǎng)h得只剩一萬字的文章一樣欲账,那篇文章發(fā)布前共刪掉了四萬個(gè)字。
WWDC<T>沙龍活動(dòng)
可想法總是很容易芭概,實(shí)踐起來卻又是另一種情況赛不。我對(duì)自制幻燈片的初步設(shè)想是第一能夠前后翻頁展示內(nèi)容,第二能夠支持和 Keynote 不一樣的動(dòng)畫效果和頁面美化罢洲,第三能夠直接在幻燈片上進(jìn)行一些 SwiftUI 功能的交互演示踢故。
接下來就要開始實(shí)際去做了,我先拿出上周用鉛筆在 A4 紙畫的人草圖加工來豐富展示惹苗,發(fā)現(xiàn)加工的時(shí)間來不及了殿较,雖然現(xiàn)在加工速度比以前快了,但是時(shí)間太緊鸽粉,還要寫幻燈片程序呢斜脂。SwiftUI 開發(fā)確實(shí)快,每個(gè)頁面我都寫成一個(gè) View触机,標(biāo)題帚戳、大綱和示意圖的組合我做成了通用 View,通過傳入不同標(biāo)題儡首、大綱數(shù)組和圖片數(shù)組來展示不同頁面的內(nèi)容片任,定義一個(gè) ObservableObject 的類 GlobalStateInfo 作為 View Model 來存儲(chǔ)需要的狀態(tài)數(shù)據(jù),比如當(dāng)前在哪頁蔬胯,當(dāng)前文字顏色对供,當(dāng)前頁背景顏色等,每個(gè) View 里使用 @EnvironmentObject 就可以去獲取和設(shè)置 GlobalStateInfo 了氛濒。
關(guān)于為了傳遞數(shù)據(jù)产场,是直接調(diào)用 EnvironmentObject,還是通過子視圖傳遞 ObservedObject舞竿,兩種方式哪個(gè)更好京景,在 WWDC21 的 Digital Lounges 里,蘋果工程師的回答是兩者用途不同骗奖。當(dāng)大部分 View 都需要用到一些通用數(shù)據(jù)時(shí)确徙,推薦使用 EnvironmentObject,因?yàn)闆]有實(shí)際使用 ObservableObject 的 View 不會(huì)被與之相關(guān)的代碼搞亂执桌。如果模型不是基于 View 層次結(jié)構(gòu)的對(duì)象圖鄙皇,使用 ObservedObject。另外還有個(gè) Digital Lounges 的問題仰挣,是問怎么從舊的 AppDelegate/SceneDelegate 生命周期轉(zhuǎn)換到新的 SwiftUI 2 生命周期伴逸。蘋果工程師說可以使用 UIApplicationDelegateAdaptor 屬性包裝器,SwiftUI 將實(shí)例化你的 UIApplicationDelegate 的一個(gè)實(shí)例膘壶,并以正常方式調(diào)用它错蝴。更詳細(xì)的解答和其他的話題可以參看這篇SwiftUI Lounge QAs博烂,內(nèi)容都是 roblack 從 Digital Lounges 里摘出來的,WWDC21 那幾天我也在 Digital Lounges(報(bào)名早)看大家和蘋果工程師的互動(dòng)漱竖,后來看別人說 Digital Lounges 的 SwiftUI 那場爆滿,已經(jīng)超負(fù)荷運(yùn)轉(zhuǎn)了畜伐,感覺蘋果最近變得更開放了馍惹,很多蘋果工程師都開通了 Twitter 賬號(hào)在 WWDC 期間積極和大家互動(dòng)。
為了使頁面不單調(diào)玛界,我打算每頁大綱的顏色做些區(qū)分万矾,發(fā)現(xiàn)11頁每個(gè)都配一遍看效果時(shí)間太緊,于是我選擇了一些背景色通過隨機(jī)讀取慎框,每次看到的顏色都是不同的良狈,由于都是一個(gè)一個(gè)手動(dòng)選出來的,所以不同組合效果也不會(huì)太差笨枯。
現(xiàn)在前后翻頁展示內(nèi)容這個(gè)想法是完成了薪丁,這也是 SwiftUI 開發(fā)的優(yōu)勢,能夠快速構(gòu)建頁面架子和簡單的數(shù)據(jù)頁面同步設(shè)置馅精。但是第二個(gè)想法严嗜,完成起來就非常費(fèi)時(shí)費(fèi)力且不那么順利了。
首先說下字體洲敢,系統(tǒng)默認(rèn)字體很正式漫玄,以往我都是直接用 iPad 手寫,但是這次時(shí)間緊沒法一個(gè)字一個(gè)字的寫了压彭,所以我打算選擇其它字體睦优,View 的 .font 修改器可以選擇其它字體,方法是 .font(Font.custom("font-name", size: 110))壮不。如果直接在Finder里查看字體沒法得到可用的字體名汗盘,需要使用 NSFontManager.shared.availableMembers 來獲取可用字體名。
接下來是標(biāo)題忆畅,以往做幻燈衡未,經(jīng)常講到具體內(nèi)容時(shí),特別是細(xì)節(jié)時(shí)家凯,容易讓看的人忘記當(dāng)前頁主題是啥缓醋。如果標(biāo)題太大,可展示內(nèi)容就少了绊诲,及時(shí)這樣送粱,觀看的人也容易忽視主題。因此掂之,我打算把標(biāo)題做成一個(gè)循環(huán)的動(dòng)畫抗俄,這樣就可以在我展開說內(nèi)容的時(shí)候脆丁,看的人即使走神了還能夠注意到當(dāng)前頁主題。標(biāo)題的動(dòng)畫主要是控制好動(dòng)畫的時(shí)間动雹,不能太快槽卫,不然會(huì)過于吸引注意。
以前 keynote 的轉(zhuǎn)場動(dòng)畫我基本都試過胰蝠,每次來回都是那些歼培,很難和其他人做出差異來。只能靠圖和配色作區(qū)分茸塞。這次我利用每頁的內(nèi)容大綱進(jìn)入效果來作為轉(zhuǎn)場動(dòng)畫躲庄。我先將大綱列表放到 VStack 里,F(xiàn)orEach 里獲取到下標(biāo)钾虐,通過下標(biāo)獲取列表數(shù)組里的 Text View噪窘。之所有要得到下標(biāo)而不是直接獲取列表數(shù)組里的 Text View,其原因是還會(huì)將這個(gè)下標(biāo)用在轉(zhuǎn)場動(dòng)畫效果上效扫,我希望大綱列表的內(nèi)容是一個(gè)接一個(gè)進(jìn)來的倔监,需要這個(gè)下標(biāo)值來做時(shí)間間隔。Animation 的效果使用的是 interpolatingSpring菌仁,我將 damping 參數(shù)設(shè)置為0.3丐枉,這樣彈性效果更佳。列表內(nèi)容進(jìn)入的是 GeometryEffect 協(xié)議掘托,用來替代 AnimatableModifier瘦锹,通過 AnimatablePair 來設(shè)置移動(dòng)位置新舊值。直接一個(gè)方塊滑入略顯單調(diào)闪盔,使用 CGAffineTransform 里的 c 參數(shù)可以設(shè)置將矩形進(jìn)行變形弯院,會(huì)有一種被拉進(jìn)來的感覺。變形過程配合滑入動(dòng)畫再加上 interpolatingSpring 設(shè)置的彈性效果泪掀,會(huì)讓轉(zhuǎn)場更有動(dòng)感听绳。
并行執(zhí)行的動(dòng)畫越豐富,轉(zhuǎn)場感覺就會(huì)更好异赫,我想著每頁都做個(gè)不同的效果椅挣,使用 Shape 繪制一些圖形做背景動(dòng)畫,這樣會(huì)有新鮮感塔拳。當(dāng)?shù)谝豁摵偷诙撆旰笠呀?jīng)天亮了鼠证,經(jīng)過一個(gè)上午,下午就要分享了靠抑。我還沒有困意量九,因?yàn)楹竺孢€有那么多頁面沒有做完區(qū)分轉(zhuǎn)場的動(dòng)畫和配色,更別說 SwiftUI 功能的交互演示了。而且具體分享的內(nèi)容我還沒有整體串一遍邏輯荠列。一天一夜完成這個(gè)項(xiàng)目時(shí)間還是太緊类浪,當(dāng)時(shí)想著要再能多一天時(shí)間就好了。2點(diǎn)開始分享肌似,1點(diǎn)我在旁邊一個(gè)小會(huì)議室把整個(gè)內(nèi)容自己在心里試著說了一遍费就。分享內(nèi)容包括了自制低版本兼容 AsyncImage 演示、SwiftUI 那些版本兼容問題川队、SwiftUI 背后關(guān)鍵技術(shù)簡介受楼、SwiftUI 生命周期、布局呼寸、Modifier、不透明返回類型猴贰、屬性包裝对雪、Result Builder、Geometry米绕、Preview用的技術(shù)瑟捣。
其中 SwiftUI 內(nèi)部運(yùn)作的機(jī)制是每個(gè) View 都有自己的 Identity,SwiftUI 會(huì)將給 State 和 StateObject 分配內(nèi)存空間的 Storage 和 View 的 Identity 綁定起來栅干,共存亡迈套。當(dāng)相同 Identity 的狀態(tài)數(shù)據(jù)發(fā)生變化了或者和 View 依賴關(guān)系改變了,就會(huì)重新建立 View 和 RenderNode 的依賴關(guān)系碱鳞,他們之間的關(guān)系是圖結(jié)構(gòu)桑李,圖結(jié)構(gòu)可以降低依賴關(guān)系檢查復(fù)雜度。最后渲染出來窿给」蟀祝總的來說 SwiftUI 運(yùn)行原理有三個(gè)點(diǎn)最重要,Identifier崩泡、生命周期和依賴禁荒。視圖的生命周期是 Identifier 來決定的,state 生命周期和視圖的生命周期是相同的角撞。在生命周期中呛伴,state 有變化的時(shí)候會(huì)做diff,diff和渲染效率提升是使用圖型依賴結(jié)構(gòu)谒所,只渲染狀態(tài)依賴的視圖热康,如果按照 UIKit 那樣的樹形結(jié)構(gòu)做diff,效率會(huì)特別差劣领。
現(xiàn)在很多常用開源庫都已經(jīng)對(duì)SwiftUI做了適配褐隆,蘋果公司自己的App,比如天氣剖踊、相冊庶弃、快捷指令衫贬、地圖和相冊都有用到SwiftUI。以下是SwiftUI用到的語法特性:
- ResultBuilder
- ViewBuilder
- Trailing Closure
- Opaque Type
- Inline
- PropertyWrapper
- KeyPath
- DynamicMemberLookup
如果你使用這些特性也能夠再造一個(gè)兼容低版本的類似 SwiftUI 的框架歇攻。SwiftUI 最顯現(xiàn)的 DSL 技術(shù)使用的就是 ResultBuilder 語法特性固惯,Result Builder的提案SE-0289 里有詳細(xì)的描述,通過 Result Builder 下面的方法可以自定義出一個(gè)簡潔的 DSL 出來缴守,提高特定業(yè)務(wù)開發(fā)效率葬毫。
- buildBlock:構(gòu)建基本語句的block組合結(jié)果。
- buildExpression:可選屡穗,給表達(dá)式提供上下文類型信息贴捡。
- buildOptional:對(duì)沒有else的if語句支持。
- buildEither:構(gòu)建選擇語句不同結(jié)果村砂。通過條件結(jié)果折疊成一個(gè)結(jié)果烂斋,實(shí)現(xiàn)對(duì)if-else和switch語句的支持。
- buildArray:將所有迭代結(jié)果合并成一個(gè)結(jié)果的方式實(shí)現(xiàn)對(duì)for...in語句的支持础废。
- buildFinalResult:可選汛骂,可以調(diào)用頂層函數(shù)體的結(jié)果進(jìn)行處理,產(chǎn)生最終的返回結(jié)果评腺。
- buildLimitedAvailability:會(huì)在if #available的block部分結(jié)果上調(diào)用帘瞭,使result builder可以擦除類型信息。
這次的 WWDC 還專門有個(gè) Session 講解了怎么用 Result Builder 來做 DSL蒿讥,這個(gè) Session 是 Write a DSL in Swift using result builders蝶念。
Swift 視圖返回的類型是不固定的,因此使用了 Swift 的不透明類型語法特性來進(jìn)行支持芋绸,支持其返回帶有大量泛型參數(shù)的龐大類型祸轮,這個(gè)類型中還包括了 Result Builder 中的 if 條件類型值,支持多分支類型侥钳。Opaque Types的提案在這里SE-0244适袜。
跟著視圖后面的點(diǎn)語法是 modifier,每個(gè) modifier 都會(huì)在視圖樹中新建一個(gè)層舷夺,因此 modifier 的寫的先后順序不同苦酱,效果是不一樣的。
對(duì)于數(shù)據(jù)的監(jiān)聽和響應(yīng)使用的是 swift 里的屬性包裝語法特性给猾,屬性包裝的提案是SE-0258疫萤。包裝后數(shù)據(jù)的使用就方便了很多,對(duì)于不同屬性包裝類別的選擇可以按照數(shù)據(jù)類型和應(yīng)用場景來敢伸,對(duì)于值類型扯饶,如果是只讀的數(shù)據(jù)可以什么都不加,如果數(shù)據(jù)是可讀寫的,使用@State尾序,如果數(shù)據(jù)是需要在其他視圖進(jìn)行讀寫并自己也同步響應(yīng)的钓丰,使用@Binding進(jìn)行聲明。對(duì)于對(duì)象類型的數(shù)據(jù)每币,指向?qū)ο蟮囊媚馨l(fā)生變化要用@ObservedObject來聲明携丁,引用不可改變,那么就用@StateObject兰怠,使用環(huán)境傳遞對(duì)象用@EnvironmentObject梦鉴。
完整的 WWDC<T>沙龍活動(dòng)回放可以掃下圖中的二維碼:
下面是當(dāng)時(shí)現(xiàn)場演示的部分幻燈片,動(dòng)畫的效果可以看上面的視頻回放:
至此揭保,這篇WWDC21見聞就寫完了肥橙,詳細(xì)描寫自己WWDC21期間的一些獨(dú)特經(jīng)歷和其中涉及相關(guān)技術(shù),這樣會(huì)讓文章的獨(dú)特性和真實(shí)感有很大的提升秸侣。
對(duì)獨(dú)特性和新意的思考
通篇看下來存筏,你是不是感覺到故事性和真實(shí)性其實(shí)是非常容易做到的∷危可以理解為只要努力些,時(shí)間再長些名秀,這兩點(diǎn)就能夠完成励负,且能線性得到提高。只埋頭做事情比較容易和舒適匕得,但一直這么干继榆,熵就會(huì)越來越多,不可逆的無用能量無法排除汁掠。而獨(dú)特性意味著你會(huì)去體驗(yàn)適應(yīng)新的環(huán)境略吨,去獲取實(shí)踐新的認(rèn)知,去結(jié)識(shí)新的朋友碰撞新的思路考阱,使得自己體驗(yàn)到不同以往的經(jīng)驗(yàn)翠忠。新意成功幾率很低,非線性的乞榨,類似于基因突變產(chǎn)生的進(jìn)化秽之,這和努力無關(guān)。新意和獨(dú)特性一樣屬于逆熵過程吃既,不能忽視考榨,大跨步的進(jìn)步需要對(duì)傳統(tǒng)的顛覆。新意會(huì)帶來新的獨(dú)特經(jīng)歷形成一個(gè)新的循環(huán)鹦倚,不去嘗試就不會(huì)有新的機(jī)會(huì)河质。
如果把本文當(dāng)成一篇筆記,其間又融入了寫作心得;如果把本文當(dāng)做一篇寫作心得掀鹅,其間又穿插了大量筆記內(nèi)容散休。你說這是不是也是一種新意呢。
對(duì)于新意淫半,我印象最深的還是權(quán)力的游戲的血色婚禮溃槐,神來之筆,當(dāng)Joffrey正最可氣科吭,少狼主正得勢時(shí)昏滴,劇情完全打破傳統(tǒng),效果非常震撼对人。凡人皆有一死谣殊,凡事皆有可能,于是乎對(duì)后面劇情的推進(jìn)更加期待了牺弄。而這個(gè)新意是建立在整個(gè)劇對(duì)真實(shí)感上的毫不含糊姻几,包括了扎實(shí)的世界觀構(gòu)建,服飾道具高度的還原势告,完全把觀眾帶入了故事中蛇捌。另外作者對(duì)古歷史的專研和記者經(jīng)歷的結(jié)合產(chǎn)生出的鮮明的人物刻畫和獨(dú)特的劇情設(shè)計(jì)也是本劇的骨架支撐,獨(dú)特性的體現(xiàn)咱台。
Finally
今天我說的這些心得可以作為下筆“記錄和分享”技術(shù)的一個(gè)契機(jī)络拌,但是對(duì)于自己技術(shù)的成長,寫文章并不是最終的目的回溺,寫作是你對(duì)自己思想的研究和開發(fā)春贸。文章的上限是你的技術(shù)能力,文章只是讓人了解你技術(shù)一種手段遗遵。因此更重要的是你做的技術(shù)是否有突破有演進(jìn)萍恕,獲得應(yīng)用,并在產(chǎn)品中取得了好的效果车要。還有那些孤獨(dú)著研究技術(shù)的時(shí)光允粤,經(jīng)歷著一直努力著奮斗著卻一直不被看見,得不到認(rèn)同翼岁,也沒有結(jié)果的歲月维哈,還能夠一直被自己的熱情感動(dòng)而不放棄去取得一點(diǎn)點(diǎn)進(jìn)步帶來的滿足感。