2022-08-20 原《每周读书》系列更名为《枫影夜读》

2014 年 6 月 美籍华裔女作家伍绮诗(Celeste Ng)的首部小说 Everything I Never Told You 在美国出版,迅速受到美国读者关注,成为 Amazon 2014 年最畅销小说。今年(2015年)7 月简体中文版正式登陆中国,于是出版社与各大媒体争相造势,什么“中国女作家跻身美国文坛”、“打败斯蒂芬金成为 2014 年亚马逊最畅销小说第一名”之类的新闻比比皆是。
这些媒体不要脸的吹捧我们且抛下不理,单就《无声告白》一书来说,作者的写作技巧非常成熟,擅长人物塑造与情感描写,通过 6 个各不相同的主要人物把异类、歧视、压力等话题发挥得淋漓尽致。尽管此书水平不错,但是单就一次 Bestseller 并不能代表作者就真的在美国文坛占有地位了,我们拿之前 The Martian (每周读书 七十一 Andy Weir《The Martian》)在 GoodReads 上的数据对比,The Martian 有 176,258 ratings,28,212 reviews 而 Everything I Never Told You 只有 55,435 ratings,6,812 reviews(截至9/3/2015)。已经算很多人关注的小说,但并没到疯狂的地步。
回过来看作品本身。小说第一章展示了一个美好的美国混血家庭,以找不到女儿 Lydia 为契机,使第一章处于纷乱与麻烦之中,最终以警察抽干湖水发现 Lydia 的尸体结束本章,情节非常紧凑,轻描淡写之间描述了由白人母亲与中国父亲结合的家庭,以及家里 Lydia 集所有聚光灯于一身的地位。不得不说,这个开头非常漂亮!
带着“Lydia 死因未明”的主题悬念,作者开始为我们展示父亲 James 的家庭背景:上世纪 60 年代年幼的他随着偷渡打工的父母亲到美国,从小在学校就被视为异类,一直渴望却永远无法融入大家。以及母亲 Marilyn 的家庭:她有位传统的母亲,她自己一直渴望过得与母亲不同,却因为是女性的身份而郁郁不得志。
这些背景故事单独拆分都可以写出不错的情感故事,但是作者拖着“Lydia 死因”这个悬念却一直在讲述她父母亲的故事,回忆的部分太啰嗦,令人感觉情节拖沓,类似火影的“回忆杀”。但是这一部分又是后面情节发展的必要铺垫,不可或缺,如果作者处理得好应该可以更简洁一点,或者处理得更起伏得当一点,就是说:你可以做背景描述,但是不要描述得太无聊。我觉得这一部分当是全书写得最差的地方。
作者为每一个主要人物都准备了大量素材,用于表现他们在社会群体中被排挤,被欺负,被歧视等苦痛,但是过于细碎,作者擅长细节描写,尤其是以小女儿 Hannah 童稚的视角看到的世界,令人叹服,却不怎么擅长组织起所有的细碎的材料,在表现 James 与 Nath 相关背景故事上堆积了诸如泳池、运动会等故事,却没有层次感与递进感,与其堆砌所有的材料,还不如只选择最具有表现力的几个场景。这种琐碎的分散感还体现在几个主要人物的份量上,从故事上来看 Lydia 无疑“应该”是最重的主角,因为她是这部小说的开篇,她的死因是整部小说的主线悬念。但是她的死因与家庭的每个人都有关联,于是作者又花费了大量的笔墨在父母亲与哥哥 Nath 身上,一旦写到父母亲就必须写父母亲各自的家庭,很容易就分不清轻重。如果每个人物都是主角,这本书就没有主角。
而说到本书情节最紧凑,情感起伏最大,每一个人物的表现都有血有肉又哭又笑生动活现的部分,应当是 Marilyn 离家出走去实现自己读完大学成为一生的梦想,但发现自己又有了第三个孩子不得已回归家庭的那一刻。在这个支线中,每个人物的性格、地位与内心的渴望都得到淋漓尽致地表现。
Marilyn 渴望摆脱母亲的命运,渴望与众不同,渴望成为医生,但是与此同时,又与其他普通人一样在医院里看到女医生会觉得奇怪,这种矛盾的心理赋予了 Marilyn 鲜活的人性。
James 则渴望融入社会,渴望别人接纳自己,一生生活在自己受尽排斥的阴霾之中,看到儿子 Nath 逐渐成为自己当年的影子他开始疏离儿子,而妻子 Marilyn 无故地离家出走又让他觉得果然白人是看不起中国人的,跟他结婚就是不应该的,多年的疮疤再度被揭开。
还有女儿 Lydia,脆弱的内心一直单纯地祈祷让母亲回家,只要母亲回来就好,于是这种渴望在母亲回家后成为 Lydia 内心最大的负担。好在有哥哥 Nath,这个习惯了被父母忽视的男生,自立自强,一直坚信有一天能够离开这个令人不开心的家庭,找到自己的自由。
我觉得这一段真是全书写得最精彩的一段,每一个人物都各有牵绊,各有自己的打算,各有自己的悲伤。而 Marilyn 的离家出走以及回归,则使各个人物后面的心理发展成为自然。情感的澎湃在孩子们呆视母亲仿如陌生人,又肆泪拥抱母亲的那一刻达到顶点。
这一段大约在全书 50% 的位置,这个位置是个分水岭,前半部分除了开头之后情节拖沓,但是交代的背景又不可或缺,后半部分有了前面的铺垫,展开来顺风顺水,自然得多,只是还稍微嫌有点太长了。
最后故事的结尾在 Nath 和 Jack 在湖边的打架结束,Nath 沉入湖底,感受了妹妹当时的感受,随后又浮出水面,“太晚了。他已经学会了怎样不被淹死。”
我觉得故事的结尾有些过于平淡。按照作者开篇的悬念来写,如果把 Lydia 的死因放在最后揭示会更令人感动。作者在书中把 Lydia 深夜划小船到湖中央的原因处理成是给自己一个借口,从来不会游泳的她如果能够游到岸边就重新开始新的生活,否则就让一切都结束吧。这种解释始终有点牵强,毕竟带有的乐观成分太高,而 Lydia 给人的感觉是她已经受够了这个高压炉了,她已经完全受不了了。
一个好的开头可以让这本书卖得不错,一个好的结尾可以让你的下一本书卖得不错。这本书的开头不错,中间部分有点拖沓但很令人感动,如果结尾能够再掀高潮就更好了。
15.09.03/夜
于自宅
2022-08-20 原《每周读书》系列更名为《枫影夜读》

自 1985 年出道以来,东野圭吾每年都能保持 3—5 本作品的发行,真不愧是名副其实的高产作家。这本《恶意》是东野 1996 年发行的 5 部作品之一,同年的作品我只读过短篇集《毒笑小说》,那部作品差强人意,并不怎么有趣。
然而《恶意》却以其机巧的反转设计,特别的叙事结构,多元的人物塑造,以及时不时穿插的揶揄讽刺,深深地吸引了读者。从此作我们可以看出东野已跳脱本格派推理的“凶手是谁”的悬念,转而在凶手动机的追查上巧设机簧。
《恶意》一书围绕“校园暴力”的主题展开,这是一个大多数人都非常熟悉的话题,经历过校园暴力的人,无论是欺负者还是被欺负者,都很难忘记那段经历,于是这本书就很容易引起读者的内心共鸣。虽然现实生活中大多数校园暴力并没有小说作品中的严重,但是类似事件还是会给年少的内心留下深刻的阴影。(比如枫影现在还会很清晰地记得中学时被人欺负的场景,泪目。)《恶意》抓住这个特别残忍却又容易被世人忽略的话题,制造了一起极端的事件,发人深省,读罢全书,令我印象最深的不是东野炉火纯青的写作技巧和一波三折的反转,而是这个司空见惯的话题下世人习以为常的冷漠,东野抓住了这个病态的“日常”,笔锋犀利,入木三分。
枫影非常喜欢技巧漂亮的作品,比如独倚望江楼的周邦彦,比如马蹄声洒落在街上如白色小花的何其芳,东野的作品同样漂亮,不在辞藻的雕琢,在故事的结构。
《恶意》九章,各以不同人物自己的手记、回忆、自白来写,翻开此书的第一页我就想起阿加莎的《罗杰疑案》,这部作品也是比较特别的以凶手的第一人称视角来写的,所以看到本书的第一段就已经知道凶手是谁了,好在这本书凶手是谁并不重要(笑)。这样的写法好处非常明显:因为是第一人称视角的手记,可以随意布置盲点?(反正是从我嘴里说出来的,从我的笔下写出来的,做不得真)。基于这一点,作者才得以在本作中自由反转,一层又一层,给读者带来畅快的情感体验。
为了实现多人视角的叙事结构,作者需要倾注相当的精力。虽然凶手与被害人只有那两个固定的名字,但是反转的故事一定有对立的人格,每一个人格都需要相当的思虑与设计,才能成为一个血肉丰满的人物,否则就是空洞的白纸,所以作者至少要设计两个对立性格的凶手,以及两个截然不同的被害人。除了警官加贺恭一郎的性格可以不变外,这本书的三个主要角色就得有五个性格。再加上配角们,加上第七章加贺去调查当事人周边的人的访谈。每一篇简短的访谈都是一个个性鲜明的人物,仅仅从谈话的语气就需要分辨出这是个什么样的人物,虽然相对于长期存在的配角来说,这样的人物只要访谈一结束就可以消失了,但是塑造这些谈话还是需要一定的精力。这是视角切换带来的缺点,作家需要设计的人物变多了,但是可以看到作家在此作中可谓游刃有余,这就需要作家平时有一定的积累。这让我想起《毒笑小说》这本短篇集,当时给我的感觉就是:这大概是作家平时积累的写作素材拿出来热一热就发表了的吧。
除了人物之外,《恶意》中还出现了几处“故事中的故事”这样的设定。由于本作的主要事件与小说作家的作品相关,难免会描述几个作品的内容,这里虽然只是提到故事梗概,但每个故事都十分完整,足见作家平日的构思,尤其是核心作品《禁猎地》,把“校园暴力”的故事以被害人作品这样的形式写出来,比起直接叙述被害人的经历要更令人信服。还有本作中穿插的对教育界的揶揄讽刺也是景上添花的闪光点,比如“老师和学生的关系建立在一种错觉上,但是维持这种错觉对双方而言都是幸福的事情”,类似这样的论点在书中有几处,文笔非常犀利。
自此,我们可以说《恶意》是一部技巧成熟,立意高远的作品,然而,就如书中加贺警官所说:
解释得通和百分百信服是两码事。
推理小说如果逻辑不够缜密则容易给读者留下无法信服的印象。有的读者喜欢追查推理小说的蛛丝马迹找出逻辑漏洞,我对这方面兴趣不大,但是有一点始终觉得不太舒服:就是凶手野野口修的真正动机。
他背负着少年时期“校园暴力”受害者的包袱,又经历过“被迫成为协助强暴同学”的帮凶,这段经历确实足以成为他内心的阴影,再加上被害者日高以德报怨的帮助,他自身的妒忌、癌症等多方面因素的侵扰下,野野口成为真凶的动机可以说是很成熟的。但是,作者刻意采用的多人第一人称视角切换的写法,却恰恰漏了“真实的野野口”这一视角。读完全书,我依然非常好奇真实的野野口修到底是什么样的人物,他的性格应该十分阴沉,善于演技,而且善于写作,而且内心的扭曲应该是世人无法想象的,我们能想象的是,他一定有一套自己发展出来的扭曲但是坚实的三观。这一个视角如果写得好的话,我认为比起以加贺的角度去解读野野口的心理,要更加令人震撼。
但是很可惜作者并没有写下“真实的野野口”这样的视角,连一次以这样身份的对话都没有,说得好听叫“留下悬念”,说得不好听就是“结尾太仓促了”。
最后我想说瑕不掩瑜,这部《恶意》依然是东野圭吾非常优秀的作品,即使带着“没有真实的野野口的叙述”这样的遗憾,也不妨碍它成为与《白夜行》并列的好作品。
15.08.30/下午
于自宅
2022-08-20 原《每周读书》系列更名为《枫影夜读》

我们说东野的作品最大的亮点在于社会问题与人性的探讨,但是他并不是从一开始就写这些话题的。出道作《放学后》就是经典的推理小说,重点在“凶手是谁”这件事情上,到了后来小说《宿命》被称为是创作风格的分水岭,从此以后,凶手不再是小说的主题,“凶手的动机”成为他作品中的主题悬念。以此为契机,东野创作了《白夜行》、《幻夜》、《秘密》、《嫌疑人x的献身》等作品,这一时期的东野可谓是人生巅峰。
这本 2014 年的作品《虚无的十字架》秉承了东野一贯的做法,在推理的形式上,探讨了一个很大的社会话题——死刑。
死刑是古已有之的最高刑罚,在几乎所有的人类社会里都有死刑这种刑罚。近年来废止死刑作为社会话题一直被人反复探讨,并随着各种严重刑事案件的出现成为一时话题,比如药家鑫案就曾引发人们对废止死刑的热烈讨论。其实废止与支持死刑就像一场辩论比赛,正反双方各有道理,没人能说出绝对的黑与白。
东野在《虚无的十字架》这部作品里,从遗族(受害人家属)的角度出发,进行了一系列探讨。探讨的话题也离不开正反双方集中讨论的几个论点:
支持死刑的人认为杀人偿命,天经地义,对于杀人犯来说,死刑是最符合善恶报应的结果。反对者则认为无期徒刑的惩罚性比死刑要高,而且政府本身没有权力剥夺人的生命,法律也不是作为报复的手段,监禁教化犯人是比简单粗暴地死刑更好。
知道罪犯被执行死刑,对于受害人的遗族可以有一定的心理安慰。但是反对者认为死刑事实上并没有实质性的帮助,死者不能复生,把罪犯处死了受害者也没能活过来。
支持者认为死刑可以彻底隔离罪犯,反对者则认为无期徒刑加上不得假释也可以隔离罪犯。
支持者认为如果司法公正严谨,则极少可能会产生误判,反对死刑者认为无法完全避免误判,而一旦冤杀则永远无法补救了。
《虚无的十字架》从遗族的内心出发,作为失去独生女儿的父母,当然希望罪犯接受死刑:
要求杀人凶手自我惩戒,根本就是虚无的十字架。然而,即使是这种虚无的十字架,也必须让凶手在监狱中背负着。
但随着故事的发展,这位坚决的母亲在态度上发生了转变,事实上也就是支持派与反对派的斗争。小说各自挑了一个对支持派与反对派有利的案例来展开,在“是否应该废止死刑”这样一个根本没有答案的话题上,作者非常鸡贼地把诠释地交给主角,以主角的角度含糊地带过。所以是“死刑话题”赋予了东野这部小说不错的思想内涵,同时也是这个话题的无法解答使得这部小说不够深入。作为一个文学作品,不管是正方也好反方也好,只要作者的信念足够坚定,作者本身相信了这个观点,就能灌注给这部作品相当的活力与深度,但是由于作者本身的犹豫导致主角的犹豫,由于主角的犹豫导致作品流于表面。
从《白夜行》探讨孤儿、恋童癖与社会不平等问题,到《红手指》探讨老人赡养问题,到《秘密》探讨性倒错问题,作者在这几个话题上都有明确的个人立场,所以这几部作品给人气场很强,坚不可摧之感,但是《虚无的十字架》由于作者自己也给不出明确的答案,我只能说,故事讲的不错,有东野一贯的水平,但是过几天我肯定会忘了。
15.08.23/下午
于时光 Cafe
今天已经是 2015 年的第 237 天了,今年里你读了几本书呢?最近两个月里,枫影读到了不少好书,其中当首推来自以色列青年才俊的《人类简史》,作者超然物外的三观深深令人折服。然后来自美国女作家 Gabrielle Zevin 的小说《岛上书店》也是不错的读物。
至于莎翁的《四大悲剧》由于年代久远,可能会略显沉闷,却是了解这个英文文学巨匠的不错选择。海子和魏宁格的故事颇为相似,两人都是思想与故事比作品有趣的。
以下是这八周来的书单:
2015-06-27

一开始觉得莎翁作品难读,其实他是16世纪人,用的现代英语,懂得几个thy, thou, thee之后就没有什么问题了,而且他写的是要上演的戏剧,情节紧凑曲折,再且中译本有民国才子朱生豪的版本,通俗易读。所以读莎翁的戏剧就跟读小说一样。
2015-07-09

作者在全书中贯彻这种超然物外的三观,令人叹为观止。而且值得一提的是,中信的这部译本,质量非常高,语言晓畅,而且作者还为中国版做了内容修改,加入了大量跟中国历史相关的资料来印证他的观点,据说他对每一个国家的版本都做过修改,简直神人。
2015-07-16

虽然这本带有很强总结目的书并不值得去读,但是“为你读诗”的出现是一个好的兆头,希望诗歌这种美丽的文体能够重新受到大众的欢迎,催生更多有才华的诗人。
2015-07-23

大多数读者应该都听过《面朝大海,春暖花开》,听说过海子卧轨,实际上,正是 1989 年 3 月 26 日这个沉痛的日子,让海子成为这个时代的神话。
2015-07-30

在课堂上我们往往把作家、作者与他所处的时代孤立了,把活生生一个大文豪讲解得苍白无趣。要欣赏一个作家或者一个作品,一定要放回到当时的大舞台上去,纵观时代变迁给文坛带来的变革,横观百家争鸣山川社稷给作者带来的影响,才能真正体会到作品的精妙之处。
2015-08-06

我们通过阅读知道我们并不孤独,我们阅读因为我们孤独,我们阅读所以我们不孤独,我们不孤独。“No Man Is an Island; Every Book Is a World.”
2015-08-13

几年前我在朋友圈里看到陈坤写了《突然就走到了西藏》这本书,当时我的内心就是这种想法:“一个演员,居然还写起书来,书名还故作文艺。”(其实真正的心理是:一个有名的演员,居然还写起书来,太厉害了,对比之下,我实在太没用了。)
2015-08-20

以前不理解“同性恋”存在的原因,毕竟无法繁殖后代,对物种的延续是致命的,直到读了《性与性格》,按作者的理论来说,其实本来就没有所谓的男女,以绝对男性与绝对女性为两端,人类的每个个体都只是这条线上的某一个点,于是一切就都可解了。

虽然日常阅读以 Kindle 为主,但家里还是攒了很多纸质书,每次搬家都特别痛苦,就想还不如送给有兴趣阅读的人。
有兴趣的读者请回复:我想要+“书名”(公平起见每个人选两本吧)。我会找最先回复的小伙伴要邮寄地址。T.i.T 创意园内可以免费送货,其他地区的小伙伴就邮费自付吧。
周末整理出来的书以设计类(原研哉、隈研吾、田中一光)和小说类为主,共 15 本书。
一、设计类
没看完于是没写书评╮(╯_╰)╭
没看完于是没写书评╮(╯_╰)╭
这本书更像是字典,就完全没写书评了
二、小说类
没看完于是没写书评╮(╯_╰)╭
三、其他
2022-08-20 原《每周读书》系列更名为《枫影夜读》

魏宁格坐在书桌前,昏黄的灯光映在他年轻的脸上,指尖握住的钢笔凝在空中,他此时格外平静。
也就格外纷扰。
唯有心怀平静才能感受纷扰。
今夜无雨,旅馆外的夜空深沉地望着大地,沉默得可怕。魏宁格想起多年前的雷雨夜,就在这家旅馆,一个伟大的人物在病榻上奄奄一息。忽然一声雷响,伟人朝空中怒挥右拳,仿佛扼住命运的交响曲,然后身体跌落尘世,灵魂从此升上维也纳深沉的夜空。
贝多芬。
魏宁格吸一口气,终于下笔,写下两封书信,一封给他的父亲,一封给他的弟弟 Richard。他把信装好,站起来,仔细整理了一下自己的衣装,心中一阵苦笑:“租下这个房间的时候还跟老板娘保证过绝不会闯祸的,对不起了,老板娘。”
抬眼望见镜中人的脸,5 年了,似乎没多大改变。5 年前,魏宁格来到维也纳大学,修习哲学与心理学。他热衷于思考致难的哲学问题,两年前他拿着论文《Eros and the Psyche》去找弗洛伊德的时候还满怀期待,却被泼回一头冷水。后来这篇论文被改写为《性与性格》,凭此成功拿到维也纳大学哲学博士学位。数月前,基于这篇论文的书经过重重阻隔终于面世,但是这本书既没得到强烈的批判,也没有获得预期的轰动。
心静如水。即使这本书没有成功也好,即使被指抄袭被所有人误解也罢,是时候了。
魏宁格整理好自己的衣装,摸了摸手中的枪杆。
第二天被发现的时候,他躺在旅馆的地板上,衣着整齐,一颗子弹穿透了他的心脏。
魏宁格的故事跟海子有点相像,都是非常有才华的人,海子 15 岁进入北大,魏宁格 21 岁写出惊世骇俗的《性与性格》;都是生前不为人所理解的人,海子生前难以出版诗歌,魏宁格多次求出版社出书无果;都是死后声名鹊起的人,海子卧轨而成名,魏宁格自杀而本书轰动一时。这两位都是时代的悲剧。
《性与性格》这本书出现的时代,在中国,正是清朝末年,刚签订《辛丑条约》不久的动荡时代;在欧洲,正是资本主义崛起,列强争夺殖民地的时代;在全球,正是暴风雨前的平静,一战即将爆发的时代;在维也纳,这是被称为“世纪末维也纳”的文化繁荣的时代,是诞生了佛洛伊德,诞生了维也纳分离派的时代。
以前我不理解“同性恋”存在的原因,毕竟无法繁殖后代,对物种的延续是致命的,直到读了这本书,作者认为世界上没有绝对的男性也没有绝对的女性。以这两者为极端,人类的每个个体都是这条线上的某一个点,是 M 因素与 W 因素的混合体。

以作者的这种角度来看,“同性恋”是不存在的,每个人都是“同性恋”,这种“雌雄同体论”在西方学术界的影响很大。魏宁格拿着本书的初稿去找弗洛伊德的时候,弗洛伊德只是否决了他的观点,却并没有说出他自己也在研究雌雄同体论(bisexuality)的事实,这点上弗洛伊德不太厚道。
全书读下来,第一部分最好读也最精彩,这一部分也是作者得以获得博士学位的部分。作者从生物学和心理学的角度层层剖析了男性与女性的区别,最重要的就是上面所述的,一个现实社会认为的男性也会有女性的元素,女性也会有男性的元素。现实社会仅凭生殖系统就对男女强加各种奇怪的社会偏见实在太过粗暴,比如男人一定要凶猛强悍,女人一定要温柔细心,以魏宁格的性别区分法来看,这种粗糙的见解真是太可笑了。更极端一点,对于“性倒错”(有男性生殖系统但认为自己应该是女性的人,或者反之)的群体来说,如果大众都接受这种魏宁格式的性别区分,而不是仅凭生殖系统就妄下断论的话,他们甚至可以不用做出如变性手术这种痛苦的选择。
我们可以说魏宁格的“雌雄同体论”未必正确,但是从他提出的观点出发去解释“同性恋”,去解释“性倒错”,则远比前段时间美国最高法院通过“同性恋”的理由要容易接受的多——一个 M 因素较多的人与一个 W 因素较多的人结婚了,多么正常。
但是这本书也有自相矛盾的地方,魏宁格自己说了男女的区分应该抛弃过去那种粗糙的方法,但是第二部分开始却频频向女人发难。即使我们以“绝对的女性”这种概念来理解他第二部分中所说的“女人”,也会发现很多不对劲的地方,比如”母亲“这个概念,事实上只有日常认为的“女人”才有生育能力,我们很难说魏宁格不是以现实的标准在指称书中的男人女人。
而且第二部分开始大量涉及哲学、逻辑,有许多深奥的概念,作者似乎直接把读者当做哲学系的学生,不做任何解释直接就用上了,读起来非常吃力。而涉及术语的翻译就更加难懂了,事实上第二部分我根本没有耐心全部读完,后半部分都是直接浏览带过。
我觉得《性与性格》这本书在 19 世纪末的出现有它应当轰动的价值,即使没有魏宁格的自杀也是,尤其是第一部分的论述非常精彩,值得一读。但是第二部分就明显感觉到时代带来的局限性,以及学术理论带来的艰涩,所以单就阅读体验来说,读第一部分就差不多了。
在整理魏宁格的资料的时候,我发现这本书的背景故事比它自身还要有趣。一百多年过去了,还有人深受魏宁格的影响,甚至在在法国北部一个小岛上有一位大叔还做了个网站:http://www.theabsolute.net/ottow/,上面有完整的英文版《Sex and Character》。如今魏宁格葬在维也纳新教徒公墓,墓碑上是父亲为他写的墓志铭:
此石碑下躺着一个在世上不曾寻获内心平静的男孩,
当其将己心灵的启示传授之后,在世上已找不到适合的地方。
他不停向有着最伟大思想的死亡国度探寻,
最后在一间屋子停了下来,
结束了凡间肉体的延续

15.08.16/下午
于自宅
2022-08-20 原《每周读书》系列更名为《枫影夜读》

曾走过几次长途自行车骑行,辛苦但是很令人怀念。以前我不明白这种劳累而危险的旅行吸引人的地方究竟是什么,也许是努力过后看到美景时内心的激动,也许是征服一段艰难的路程之后内心的满足,直到读了演员陈坤的这本《突然就走到了西藏》,才知道最美的原来是“简单”。
现代社会人与人之间的关系日趋复杂,这种复杂使人不愿意轻易去相信别人。许多有过长途旅行的朋友,或徒步或骑行,或登山或背包,回到现实社会都表示很难再次融入。其原因就在于:在路上的时候,每个人都是陌生人,人与人之间的关系非常简单,这种简单使得大家对待彼此更加真诚,这种真诚使得旅行的人更加感受到旅行的美好,即使有过一两次不愉快的经历,也还是愿意相信世界是美好的。因为简单,所以真诚。
陈坤的这本书,能吸引读者读下去的,大约就是真诚。
我向来很看不起认为“码农”只能做“写代码”的事情的人,这些人认为“产品经理”写代码是很可笑的事情,就因为人家的头衔是“产品经理”。但其实早期的互联网从业人员很多都是“全栈工程师”(值产品、设计、编程全包的人),后来为了提高效率才出现精细分工。我觉得一个工程师可以不具备“全栈”的能力,但是态度上不能看不起“做着设计的工程师”,或者“写代码的产品经理”。
几年前我在朋友圈里看到过陈坤写了《突然就走到了西藏》这本书,当时我的内心就是这种想法:“一个演员,居然还写起书来,书名还故作文艺。(其实真正的心理是:一个有名的演员,居然还写起书来,太厉害了,对比之下,我实在太没用了。)”当时有这种想法真是可耻,直到最近翻开了本书第一页,就再放不下了。
陈坤是一个有故事的人,没有故事的人写不出这样的书。开始看书的时候我对陈坤了解不多,只知道他演过《金粉世家》是个内地的名人。事实上陈坤在书里也毫不讳言他因为《金粉》成名的事情,他说他自己的人生是幸运的,同朋友去考北影结果别人没考上自己考上了等等。我觉得他的故事“有意思”,事实上他的故事正是这本书最大的亮点。
写本书的起因是陈坤在自己的工作室办了一个公益活动,带领经过层层面试的是个大学生到西藏徒步。这本书是对这场活动的记录,也是陈坤自己自传式的陈述,西藏是一个很艰险也很美丽的地方,陈坤因为自己的“暴发户”式的成名曾经迷茫过,抑郁过,他走过阴影之后决定做公益,去帮助其它人。于是带领大学生去西藏行走,期望能通过这种感受大自然的方式让这些学生对于生命有所领悟,这种艰苦的修行有时候甚至可以改变一个人的一生。而活动的第一天,陈坤就和大家大吵了一架。
陈坤的本职是一名演员,但是这本书写得明白晓畅,这点很难得。读这本书的时候,我一直在与自己的内心做对照,陈坤在书中直言自己的缺点,包括小时候形成自卑与自傲并行的人格,极度渴望被认可,稍微一点小事都可能被自己自卑的内心放大等问题。我想这些问题可能大多数人都有,随着生活的历练有的人寻找到了解决的办法,有的人则持续放大。陈坤的办法是“学会接受”,真正的认可不是来自别人,而是来自自己。
“小时候因为自卑,希望所有人都给我一点掌声,好像是在用别人的鼓励承认自己的存在;现在是,我管你们承不承认我存在,我做我自己,你接不接受无所谓。”
“小时候总是为了证明我很牛而做一件事情;现在是因为这个事本身很牛而做。”
诚然,这本书的鸡汤味很浓,但是真正的鸡汤文是给出或虚构或断章取义的的故事来导向作者的目的,陈坤的文字却能让我感受到他的真诚。
尽管陈坤今天能够说出这些话肯定有声望与财富作为底气,尽管我还是不太喜欢他把现在的自己写得仿佛十分完美,但我还是喜欢他写成名前的小故事,喜欢他写自己的内心成长过程中的小故事,喜欢这些真诚而简单的文字。
如果还有读者认为这本书完全就是鸡汤,那么我只能说,这鸡汤煲得可真好,我喜欢!
15.08.02/下午
于自宅
2022-08-20 原《每周读书》系列更名为《枫影夜读》

读《岛上书店》不觉凌晨,阳光敲醒额头的时候脑袋还在岛上跌跌撞撞,逡巡于书店老板 A.J.F 一生动人的故事,被吸引,被逗乐,被感动。爱伦坡定义短篇小说为“可以一口气读完的小说”,从这个层面上说,《岛上书店》是一部贯穿 A.J.F 一生的短篇小说。
这本书来自 Gabrielle Zevin 2014 年的畅销之作 The Storied Life of A.J. Fikry ,作者很“鸡贼”地选用了“阅读”这一话题,吸引了大批爱书的读者。主角是乡村小岛上唯一一家书店的老板 A.J.F,围绕主角身边的人都喜欢读书,这是一部关于读书的小说。从开篇 A.J.F 毫不客气地揶揄各类文学作品的时候,我已知道今夜注定无眠了。
光是围绕“读书”这件事情,这本已经值得一看,再加上作者娴熟的写作技巧,中文晓畅的翻译,这本书的可读性甚至远超许多本土作品。近年来如《冰与火之歌》、《人类简史》等外文译著,行云流水令人欣喜,可以说外文翻译腔的时代已经过去了。
读《岛上书店》的时候,一直让我回想起 James Scott Bell 的《冲突与悬念》中提及的写作技巧,Zevin 的这部作品简直就是 James 写作技巧的范本!比如典型的三幕剧结构,开场出版社销售代表 Amelia 与书店老板 A.J.F 的冲突给这本书起了个不错的开头,两位主角的形象特点十分鲜明。接着突如其来的遗弃在书店的小孩由于生母的自杀让 A.J.F 不得不收养下她,以此推入第二幕,开始围绕小孩玛雅的各种温情故事。最后以 A.J.F 自小就有的间歇性昏迷症揭开癌症告别的终幕,作者在前面埋下的悬念,比如每章开头的读书见解其实都是 A.J.F 在医院无法讲话的时候写下给玛雅的读书建议,比如玛雅的诞生之谜,玛雅生母自杀之谜,A.J.F 店里被盗之谜,都以贯穿全书的形式一步步解开,可谓深得畅销书写作技巧。
然后是每一个场景,出场的人物都没有闲着,无论是对话还是在做的事情,都是麻烦麻烦,冲突冲突,读者没有一刻喘气的机会,再辅以作者适时地幽默打趣,穿插以温情的画面,有如好莱坞商业片紧凑的节奏,令人沉迷其中不觉时光。
如果说技巧是这本书畅销的基础,那么对于各个作家与作品的见解则是锦上添花。我必须承认书中提到的绝大多数作品与作家我完全没听说过,但是没听过还能觉得点评有理,足见作者的功力。比如开篇的 Lamb to the Slaughter,作者对剧情做了简单的叙述,然后一针见血地指出一旦觉得其中有蹊跷,则整个故事就崩盘了。
这一点也正是本书的缺点:技巧让这本书可读性极佳,但是一旦读者意识到作者在使用技巧,那么沉浸式的阅读体验就会被破坏,也就是技巧太着于痕迹。写作技巧有入门到烂熟于胸再到忘掉技巧写出属于自己的文字这样的过程,一旦作者很露痕迹地去使用各种技巧,读者就会觉得像好莱坞大片一样:刺激但没什么营养,这也是“畅销书”一直为部分读者所不屑的重要原因。
这部作品着露痕迹的地方很多,比如在描写作家丹尼尔车祸的一段,刻意地引用丹尼尔在第一本书中使用现代诗风格描写的车祸场景,读到这里让人觉得作家仿佛在背后偷笑,挤眉弄眼。又比如《迟暮花开》这本贯穿全书串起 A.J.F 与 Amelia 的感情的书,真假作者的出现让人觉得过于突兀,仿佛为了冲突而冲突,为了反转而反转,只是大概觉得应该在这个地方放置一个反转了,就插入了一个真正的作者,在令读者意外之后转身离去,太不负责!
不过只要读者没有意识到这些写作技巧,嗯,那就是一次很不错的阅读体验了,毕竟作者在情感的细腻描写上太过耀眼,很容易掩盖其他的地方。比如在描写两岁的玛雅笨拙但真挚的情感的时候,一个可爱鲜活的小孩在读者面前展现,实在不得不爱。比如在玛雅第一次参加写作比赛,颁奖时既渴望得奖又佯装不屑的矛盾心理,当时我想,假如是自己来写这一段,一定会是很糟糕的平铺直叙,借景移情,因为我根本代入不到一个青春期中学生的内心,做不到以人物的视角来表达,而作者完全掌握了这些情感的细微的不同,每一个人物都有不同的个性与思考,所以可以在被写烂的亲情爱情之间找到令人耳目一新的美好。
一本小说,最重要的是要给读者一场丰富的情感体验,《岛上书店》做到了,而且给予读者关于阅读的思考,关于名作家名作品的思考,我们通过阅读知道我们并不孤独,我们阅读因为我们孤独,我们阅读所以我们不孤独,我们不孤独。
No Man Is an Island; Every Book Is a World.
We read to know we’re not alone. We read because we are alone. We read and we are not alone. We are not alone.
2022-08-20 原《每周读书》系列更名为《枫影夜读》

数月前读张爱玲、张恨水的时候发现有个“鸳鸯蝴蝶派”的派系,想起上学的时候听说过公安派、西昆派、新月派等等,很好奇中国文学派系都是怎么划分的,于是寻思要在“中国文学史”里面找找答案。
推友 @guyii 推荐了文学史的几个版本,包括作为大学教材的袁行霈版,但是 z.cn 没找到 Kindle 版,于是因缘际会开始看起这本郑振铎版的《中国文学史》,甫一开头就被作者科学求实的态度所吸引,待发现作者生活的年代在 1898 - 1958,根本解答不了我的问题时,已深陷本书无法自拔。😂
由于作者年代的关系,这本《中国文学史》实际上涵盖的内容为上古到近代文学史,现当代文学则没有涉及,并且作者讲述的近代(明清)部分有些粗略。谈到中国古代的文学,很多人心中会想起所谓“国学”,所谓古文,所谓诗词歌赋,脑中浮现的人物不过孔孟,不过李杜,“文学”实在迂腐得很,刻板得很。但这本书却出乎意料的有趣。
作者的年代正是我国思想启蒙的年代,古文学者一般被认为“权威至上”、“奉经典为至尊”,但是郑版的文学史一上来就是对前人作文学史的批评,谓“这二三十年间所看不的不下数十部中国文学史,几乎没有几部不是肢体残废,或者患者贫血症的”。谈到上古的《诗经》,作者直言这种远古的材料,“其靠不住的性质,是有常识的人都知道的”。及至后人托苏李诗名以寄烦忧,也是颇有科学论证的味道。
原以为这种类似量子对牛顿的完全颠覆只有科学界才有,没想到钻研文学者亦有此般精神。其实读了此书就知这种求实与颠覆自古已有之,比如韩愈领导的古文运动,就将散文从骈俪文中解放出来,催生了后来的变文、传奇、小说。
郑版的文学史主要集中在最辉煌的“中世文学”(东晋到明正德年间 1200 多年),详述了各个时期诗、赋、词、变文、传奇、小说、曲文体的发展,这期间大文学家很多,风格相近的也不少,但作者博览群书,深知众家之精妙,所作点评笔笔到位,不觉冗复。从上古的诗经楚辞到秦汉的散文骈赋,从沉郁雄健的曹操到高超清隽的嵇康,从深远澹泊的陶渊明到诗中有画的王摩诘,从豪放不羁的李白到艰深险峻的韩愈,从明白晓畅的白居易到暧昧朦胧的温庭筠,我们古代的文人大家留下了太多的文学瑰宝。在课堂上我们往往把作品、作者与他所处的时代孤立了,把活生生一个大文豪讲解得苍白无趣。要欣赏一个作家或者一个作品,一定要放回到当时的大舞台上去,纵观时代变迁给文坛带来的变革,横观百家争鸣山川社稷给作者带来的影响,才能得到立体的画面,才能真正体会到作品的精妙之处。比如《诗经》或古诗十九首,断不可用律诗绝句的角度来审视这些诗体尚未成熟的作品,比如《花间集》,既有开创新文体的深远影响,便不能轻易谓其绮丽浮华,言之无物。
不过限于作者时代,此书颇有些民族主义的意味,而且现当代部分的缺失不免遗憾,但本书的精华部分——中世文学——评点仍然精彩,尤其自唐以来,中国文学深受印度文学的影响,这个观点令人耳目一新,其影响之深,渗透了诗歌散文变文小说,也是学堂与课本所没有强调的。
熟悉“每周读书”的读者可能会发现每周介绍的书多是“没想到出乎意料的好读”,其实主要还是归因于我个人的读书习惯,一本书翻开几页如果不好读一般就放下不读了。人生苦短,书海无涯,选择自己感兴趣的书才是王道。
15.07.29/中午
2022-08-20 原《每周读书》系列更名为《枫影夜读》

如上周读书中所说,诗歌是非常注重形式的文体,音乐、意境与形式都是诗歌的特点。诚然诗歌若没有一定的深度则流于表面,但轻视诗歌的形式同样是不可取的。海子的诗歌倾向于朴素,没有何其芳式的优雅艳绝,没有戴望舒式的音律翩跹,没有顾城式的哲学思辩,海子的诗为什么会出名呢?
即使不读诗,大多数读者也都听过《面朝大海,春暖花开》,听说过海子卧轨。实际上,正是 1989 年 3 月 26 日这个沉痛的日子,才让海子成为这个时代的神话。在他之后,5 月好友骆一禾病逝,93 年顾城自杀,诗坛笼罩在一片死亡的阴云之中。这些诗人的死都有不可抗拒的无奈,但是这段时间也有些迷失的青年,盲目地追随他们而去,自杀在媒体的传播下似乎成了成名的自我献祭。在海子生前,垄断文化传媒的所谓“作协”并不承认海子,当时自称为“作家”的人们批评海子写长诗,甚至有无耻之徒抄袭海子的作品四处发表,令人发指。在那个时候,海子只是位郁郁不得志的教师。
他就是因为卧轨而出名的。
但他的自杀是复杂的,从他的诗歌中你可以感受到海子内心的澎湃与现实的抑郁之间巨大的矛盾与冲击,他不过是个孤独的诗人,他选择结束生命的初衷已随他而去,无人知晓。众说纷纭之中我更相信他的好友西川在《怀念》与《死亡后记》中所说的,海子的的死是由他内心的积郁所致,他与初恋的偶遇成为悲剧的导火索。
至于《面朝大海,春暖花开》,这首诗完全算不上海子的代表作,甚至跟他大多数作品截然不同。这首诗平平无奇,不说技巧,内涵上也不过是苦闷诗人的幽叹。我想或许是因为海子是一个时代的神话,有收入教材的意义,但是编写教材的人又希望收录的是阳光积极的作品,于是选择了这首看似明亮的诗。我已经忘记中学课堂上老师是怎样解读这首诗歌的,但是可以肯定地说,这首诗歌真正的意义要比字面上黑暗得多。“从明天起”、“愿你”、“我只愿”……这些词语分明道出他在昌平小屋里的寂寞与苦痛,诗歌里的敞亮的世界,其实是海子可望而不可及的世界。
海子的诗歌很少用修饰,辞藻也相对贫瘠,意象多用村庄、月亮、秋天、麦地、水以及死亡,所以他被成为“麦地诗人”。这与他早期多年的农村生活有关,但是海子的想象力弥补了技巧上的平淡。我最喜欢的是海子的短诗,朴实透着张力,抽象但不空虚,《春天,十个海子》一诗就比春暖花开要好得多。但是海子最重视的却是他的《太阳》史诗。这是一部体量巨大的诗作,海子仰慕歌德,希望写出《浮士德》一样的巨著。但是很可惜,《太阳七部书》非常难读,诗中充满莫名的愤怒和奇诡的氛围,缺乏技巧让这部长诗缺乏可读性,来自耶稣、但丁、佛陀等各种陌生文化以肤浅的角度生生插入诗中,无法给读者留下深刻的震撼与思考。歌德的《浮士德》写了 60 年,贯穿诗人的一生,这部皇皇巨著是诗人一生千锤百炼的结果,是诗人离世前的反刍。而海子一生追求的太阳,却无奈地没能达到这层高度。
但是我依然喜欢海子的短诗,尽管他认为短诗不过抒情的小作。海子生前最好的朋友是骆一禾和西川,三人并称当时“北大三大诗人”,海子死后两位好友倾力整理海子留下的手稿,希望能让海子的作品发表于世。就在海子走后七十天,骆一禾亦因病作别人世,只剩下西川一人。当时的文学界对海子仍持怀疑态度,西川也是顶着巨大的压力完成这本书的编撰,甚至成书后想要找出版社出版都困难重重。后来还是生活·读书·新知上海三联书店助力下方才得以出版。
读这本《海子诗全编》,不仅仅是读海子的创作,海子的故事,海子的人生,海子与骆一禾、西川的情谊,这些创作之外的故事与思考,使这本书饱满而充实。很有幸,读到了这本书,很有幸,认识到一个真正的海子。
在春天,野蛮而悲伤的海子
就剩下这一个,最后一个
这是一个黑夜的孩子,沉浸于冬天,
倾心死亡
不能自拔,热爱着空虚而寒冷的乡村
——《春天,十个海子》
15.07.18/下午
于自宅
作为一个程序员,绝大多数时候你都不需要关心一个类是怎么被加载进内存的。这里面 runtime linker 在你的代码还没跑起来之前就已经做了很多复杂的工作。
对于大多类来说,知道这一点就已经相当足够了。但是,有一些类可能需要做一些特殊的准备工作。比如初始化一个全局的表,从 UserDefaults 里面读取配置并缓存起来,又或者做一些其他的准备工作。
ObjC 提供了两种方法来实现这些事情:
如果你的类实现了 +load 方法,这个方法就会在类被加载的时候调用。这个调用时机是很早的。如果你是在被其他应用引用的应用(Application)或框架(Framework)里实现了这个方法,它甚至会比 main() 函数还早被触发。如果你是在一个可以被加载的 bundle 里面实现这个方法,那当 bundle 被加载的时候这个方法就会被调用。
因为 +load 方法过早被调用,所以应用起来会有点困难。很多时候有些类是要比别人更早被加载的,这样你无法判断别人是不是早就被调用过 +load 方法了。更糟糕的时候,你的应用中包含的 C++ 静态初始化函数在这个时机点是还没被调用的,如果你在 +load 里面调用了相关的代码,就很有可能会 crash。好消息是你链接的 frameworks 是保证在 +load 调用前就加载过了的,所以在这里使用 framewroks 是安全的。还有父类也是保证完全加载过了,所以使用父类也是没问题的。
+load 这个方法有一个有意思的特性,就是 runtime 会把所有 category 里面实现了 +load 的方法全部调一遍。也就是说如果你在多个 category 里面都实现了 +load 方法,这些方法都会被调用一次。这种设计可能跟你认识到 category 的机制完全相反,不过你要知道 +load 方法不是一个普通的方法。这个特性决定了 +load 是一个干坏事的绝佳场所,比如 swizzling。
相比而言,+initialize 方法就要正常的多了,通常也是一个更好的安置代码的地方。+initialize 有意思的地方在于它会很晚才被调用,甚至它有可能完全不会被调用。当一个类被加载的时候,+initialize 不会被调用,当一个消息发送给这个类的时候(译者注:ObjC 的方法调用都是通过 runtime 的消息机制,objc_sendMsg 方法),runtime 就会检查这个方法有没有被调用过,如果没有就调用之。大概可以认为是这样的:
当然真正的实现不会这么简单,还要解决线程安全之类的问题,不过大概就是这么个意思吧。每个类知会调用一次 +initialize 方法,而且只会在这个类收到第一个消息的时候被调用。跟 +load 方法一样,+initialize 会先调用这个类所有的父类,最后才调到自己的 +initialize 方法。
这就使得 +initialize 用起来要比 +load 方法更安全,因为调用时机的环境要安全得多。当然这时候的环境还要取决于第一条消息发送的结果,不过可以保证调用的时机一定比 NSApplicationMain() 要晚。
由于 +initialize 是 lazily run 的,所以这里就不是做注册事件的好地方。比如说,NSValueTransformer 和 NSURLProtocol 就不能用 +initialize 来注册自己,因为这就成了一个先有鸡还是先有蛋的问题。
这个方法适合用来做需要在类被加载后做的事情。由于这个方法运行的时候环境容错性更好,所以你可以使用的方法也就比 +load 自由得多,也因为这个方法是 lazy 调用的,所以你在这个方法中使用的资源就不会事先申请而造成浪费。
+initialize 的使用还有个小伎俩,我上面的伪代码里提到 runtime 会调用:
这就导致 ObjC 做 selector 实现的检查,如果当前类没有实现这个方法,那么父类的方法就会被调用。不只在伪代码里,实际上也是这样的。所以,你的 +initialize 就得写成下面这样:
如果没有做这个检查,如果你有没实现 +initialize 的子类,你的代码就会被调用两次。就算你没有任何子类,Apple 的 KVO 也会动态创建没有实现 +initialize 的子类。
ObjC 提供了两种自动运行类初始化代码的方法。+load 方法保证了会在 class 被加载的时候调用,这个时机很早,所以对于需要很早被执行的代码来说是很有用的。但是在这个时机跑的代码也可以是很危险的,毕竟这个时候的环境比较恶劣。
由于 +initialize 方法是 lazy 触发的,所以对于初始化设置的环境就要友好得多。只要不是在类接收第一条消息之前一定要做的事情,都可以在这个方法里面做。
2022-08-20 原《每周读书》系列更名为《枫影夜读》

一直认为诗歌与音乐一样,都是非常主观的艺术作品,一首诗始于作者而成于读者,读者的想象与作者的创作碰撞出光怪陆离的色彩,这种艺术的再创作完善了一首诗歌。本周的读书是“为你读诗”公众号推出的第一本诗选合辑,如果纯粹从书的角度来看,这本书完全不值得一读,这个公司主打也是“朗读”而不是诗歌本身,即使就“朗读”来说,由于每期邀请的嘉宾不同,朗读质量也就参次不齐。即便朗读的质量比较高的那几首,一旦诗歌被人朗读出来了,那么这首诗歌就经过了朗读者的二次创作。这就像小说里的人物,每个读者心中的形象、声线、甚至性格的细节都可能不一样,而一旦搬上荧幕,就固化成了演员所演绎的形象,已经是两个不同的作品。就这层意义而言,我更喜欢自己阅读诗歌,而不是听别人“朗读”诗歌。
但是我仍然欣赏这个公司在做的事情。首先诗歌这个文体本身决定了通常都是短小而且精美的,很符合现代人碎片化阅读和心灵寂寞的现状,“为你读诗”的出现也表明诗歌在今天恢复流行的可能。另外大众文化程度比之从前以提升不少,能够阅读诗歌、理解诗歌、获得美好的情感体验的人也越来越多,有阅读基础和需求基础,诗歌仿佛能回归潮流的样子,这也是读这本诗选的过程中能够想象的美好。但是历史从来都不是绝对因果可以预测的,只能说这本书的出版令人欣喜,但是诗歌的未来还只是混沌中的一个随机出口。
如果纯粹从书的角度来看,这本书的评价可算中等。前半部分的诗选为大家之作质量有保证,外国诗由于翻译的关系比较难做到音韵和意境俱佳,所以可读性会稍弱,最差的是少许“名人”的作品,有凑数之嫌。装帧上选用了对比度差的浅绿色来印刷诗歌本体,却用对比度最高的黑色来铺陈朗读者、作者、二维码、点评内容等信息,而且几乎每首诗都有一页篇幅用于朗读嘉宾丑陋的真人笔迹,喧宾夺主,并不晓得对读者的意义何在。由此只能说这本书是带着“总结公众号以往发过的文章”这种很强的目的性而出版的,所以不是粉丝可能都不会买账。
书中的好诗比如席慕容的《我》善用音律顿错,音乐感极强,比如林徽因的《一首桃花》则辞藻玲珑,极富美感,又比如顾城的《门前》似乎平淡无奇,情感却更因平静而饱满。至于书中读起来不顺畅的诗,大抵是没有押韵,不注意对称,也就是连基本的美感都达不上,更不用说要求音节错落,要求孕神奇于平淡等境界了。这也是本书中大家之作和滥竽之作的区别,诗歌是非常注重技巧与形式的文体,随便写几个漂亮的句子然后分行根本算不上诗。
“为你读诗”的这本书还附赠了光盘,收录了每一期的读诗视频,由于没有可以读 CD 的设备,我在公众号里听了几首诗歌的朗读。制作方很用心,请了许多文化人来朗读,而且有专门的音乐家做配乐,这点值得赞赏。然而正如我文首所说,诗歌一旦被人读出来,就是那个人的诗歌了。
诗歌作为一个在现代已经逐渐没落的文体,很难得能看到还有这么多的拥泵。虽然今天我们看到最优秀的诗歌作品还是来自于几十年前的才子佳人,但是“为你读诗”的出现是一个好的兆头,非常希望这种美丽的文体能够重新受到大众的欢迎,催生更多有才华的诗人。
15.07.10/夜
于自宅
P.S. 喜欢何其芳的人应该读《画梦录》,喜欢读戴望舒的人应该读《望舒草》,而不是这本奇怪的杂烩。
2022-08-20 原《每周读书》系列更名为《枫影夜读》

最近一位来自以色列的教授火了,生于 1976 年的他号称写了一本书叫“人类简史”,讲述几十万年前人类出现到今天的历史,通俗易懂,视角独特,简直刷新三观。这本书于 2014 年末出版后迅速风靡以色列,很快就被翻译成多种语言在全球畅销。这位传奇的作者叫尤瓦尔·赫拉利(Yuval Harari),现在在耶路撒冷希伯来大学任历史系教授,这部神书名为 Sapiens: A Brief History of Humankind,国内由中信出版社译为《人类简史》。
刚开始听说这个书名时很不感冒,后来偶然在学而优翻起开头几页,瞬间被作者新颖的观点所吸引:一直以来人类都认为自己是这个世界独一无二的物种,其实不过是自大瞎扯,历史上有过很多种类型的人类,我们不过是唯一还存活着的人种——智人(Sapiens)。我们和其他人种的关系就是同一个属里不同人种的关系,甚至有学者认为黑猩猩属和人属在生物学上是同一个属的关系。也就是说,如果尼安德特人能够活到今天,从生物学上来说,他们跟我们是不同的动物,就像我们跟猩猩的区别,他们永远学不会我们的语言,就像猫讲不了人话一样。假设他们能活到今天,基督教会认为神应该爱这些尼安德特人吗?我们的法律会认为杀害这些“人”属于杀人吗?
所以这部作品讲的其实是智人的历史,但是与严肃的著作不同,作者没有按照历史大事件年表的顺序来铺陈史料,得出各种“结论”。大的框架上,作者按照“认知革命”——“农业革命”——“科学革命”这样的顺序来编排内容,但是每一章论述的时候却是理论先行,再用历史资料来佐证论断。作者不是在写史书,简直在写哲学书。
由于本书的定位偏向科普,内容毫不艰涩,具有大众阅读基础,作者始终以宏观的视角俯瞰历史,生物学、物理学、化学、科学等等信手拈来,把观点阐述得绘声绘色,而且极富想象力,常有骇人听闻的言论发表,三观凌驾在现有大众认知之上,频频对各种大众习以为常的事情发出嘲讽。
比如智人在“认知革命”之后发展出来能够描述并相信虚构故事的能力,从而使共同相信这些虚构故事的人能够团结在一起,这也是智人在进化史上的一次飞跃,直接导致了智人统治地球,灭绝其他人种和大量大型动物。这种虚构故事的能力在后来发展成巫师神话,发展成公司、国家、法律、金融等等,所以今天我们都相信的国家和当年部落的民众相信巫师是一样的!甚至美国人崇尚的“人生而平等”也不过是“大家相信的虚构故事”罢了!从生物学上来说,每个人“生而不平等”,没有一样的人。公元 1776 年的《独立宣言》和公元前 1776 年的《汉莫拉蒂法典》的内容虽然不一样,但是都是一样的虚构故事!这种虚构的故事构成了社会的秩序,人们相信这些秩序,并不是因为这种秩序客观存在,而是因为相信它可以让人提升合作效率,打造更美好的社会。
作者在全书中贯彻这种超然物外的三观,令人叹为观止。而且值得一提的是,中信的这部译本,质量非常高,语言晓畅,而且作者还为中国版做了内容修改,加入了大量跟中国历史相关的资料来印证他的观点,据说他对每一个国家的版本都做过本地化修改,简直神人。
我们多数人的历史知识来自于学校,而学校出于政治需要总是给出模凌两可的历史,读完这本书,以前很多不理解的事情就豁然开朗了。比如说资本主义,从来我们只知道“资本主义”走不通,但是资本主义到底是什么,政治与历史课本上聱牙诘屈,繁冗无趣的解释完全无法理解。但是这本书就讲得非常通俗了,而且把资本主义产生的社会背景和当时人们的心理认知都解释了一遍,这样具有大众阅读基础,又有惊人言论的作品,怎么可能不火?
2015.07.08/中午
于 T.i.T 创意园
2022-08-20 原《每周读书》系列更名为《枫影夜读》

即使没读过莎士比亚的作品,大部分中国人也都听过这句话:
一千个读者有一千个哈姆雷特。
There are a thousand hamlets in a thousand people’s eyes.
这句话被解释成每个人对于文学作品的理解各有不同,而我却一直对这种解释持怀有疑问,一是我不明白这句话到底想要表达什么,二是我无法理解能够被一千个不同 POV 解释的哈姆雷特到底是什么样的存在。按理这种空泛的解释换了哪个角色都说得通,但为什么一定是哈姆雷特?
直到读完《哈姆雷特》全剧也没有答案,我觉得这位悲剧主角的形象一直非常鲜明,就是一个内心矛盾又优柔寡断的王子,能够对其有 10 种截然不同的解读已经很厉害,1000 种实在不知怎么生成的。更奇怪的是这句“广为人知的名言”没有人知道其准确的出处,有人说出自莎士比亚,有人说是恩格斯,Google 英文,出来相关网页全是中国人写的,不得不让人怀疑这句话是否“Made in China”,就像“太空可以看到长城”一样。后来我在知乎上提了问题,目前还没有明确的回答,有兴趣的同学可以考据一番:“一千个读者有一千个哈姆雷特”的出处是哪里?这句话是Made in China 吗?
不过开始看莎翁的“四大悲剧”却是因为 James 的《冲突与悬念》中多次提及《麦克白》这部作品。《麦克白》是莎翁最短的一部作品,《哈姆雷特》则是最长的一部。很多读者可能一听到莎士比亚内心就有些畏惧,觉得这人是古代人,写的是古代英语,像文言文一样一定很难读,而且跟《巴黎圣母院》什么的是一个时期的吧,一大堆环境描写无聊透了。这也是我对莎翁的第一印象,但是读完“四大悲剧”(《哈姆雷特 Hamlet》、《奥赛罗 Othello》、《李尔王 King Lear》和《麦克白 Macbeth》)之后却发现这些著名的戏剧跟小说一样有趣,而且完全不会难读。
首先莎士比亚创作的巅峰时期是文艺复兴后期(1600 年前后),大约相当于中国明朝中后期,这时候的英语已经是现代英语(Modern English,英语分为古英语、中古英语和现代英语三个时期,真正的古英语跟我们看甲骨文差不多)了,除了部分词语和文学表达有点陌生之外,大部分内容都是很好读懂的。
其次莎士比亚的代表作是戏剧,当时他既是演员也是剧作家,而且是剧团老板,他的戏剧是要在剧院里面上演的,除了特别长的《哈姆雷特》之外,大部分戏剧都在两个小时左右,跟今天的电影差不多,所以情节都非常紧凑,不会像《悲惨世界》一类小说,需要大量环境描写来吸引当时无所事事的读者,所以读莎士比亚的戏剧你不会觉得无聊,大部分时间都会有各种冲突冲突,麻烦麻烦,悬念丛生,欲罢不能。
最后能够让莎翁的作品产生“不好读”的感觉的大概就是翻译问题了,我读的是民国翻译家朱生豪先生的译本,除了个别词汇的翻译有点奇怪之外(比如 to act, to do, to perform 被翻译成“干、行、做”,称呼王后 Madam 被翻译成“娘娘”),大部分内容都很好读懂。不过戏剧作品中多有诗歌,中译本很难做到即押韵又优雅,所以真正想要体会戏剧魅力的还是得看英文版。英文版可从古腾堡计划(Free ebooks by Project Gutenberg)的网站上下载,这是个专门提供公版书下载的网站,比较有名的公版书都可以找到。莎翁的作品都是自由版权了,这个网站提供多种语言版本,下载的时候注意看看是否为英文版。
15.06.27/下午
时光咖啡
把《每周读书》同步到微信公众平台也有些时间了,最近八周居然能真正做到每周都读书,挺难得也令人欣慰。从 2010/12/17 第一篇开始,“每周读书”已近四年,然而令自己感觉到进步的,却是从公众平台上的第一篇读书开始。有兴趣的读者可以到文章底部扫描二维码关注我的公众号,以下是最近八周的书单:
2015-04-22

余诗抚去了《诗歌报》一类排资论辈自欺欺人的酸腐,唯有真挚充盈的情感保留了下来,悲伤却不绝望,苦痛然而敞亮。我想这种无以言尽的明亮之色正是余诗最为动人的地方。
2015-04-28

从书架上拣一本最薄的三岛由纪夫的小说买下,正好是《纯白之夜》。上海译文出版社出版的这套三岛的合集甚合我心,装帧简约,朴素干净,最赞的是这本小说没有莫名其妙的前言和后记,真是难得。 小说一个晚上就看完了,在三岛一如既往的细腻与优雅中度过,真好。
2015-05-05

看完这本小说,再回想《金阁寺》,有些想不通的地方就豁然开朗了。设若金阁寺所代表的美就是人世间通常的“男女之恋”的美,而沟口却屡屡和女人在关键时刻就浮现金阁寺的幻影而失败,那么金阁就是假面向往而不可得的女性了。
2015-05-23

毕竟《三体》的“硬科幻”部分精雕细琢无可挑剔,大情节上跌宕起伏,屡屡出人意料,所以只有人物是最好下手开骂的。这就好像普通人没接触过代码与产品设计,想要批评一个产品做得不好,往往只能动用“怎么也懂一点”的“审美能力”来指栽“配色难看”云云了。
2015-05-27

张爱玲的文笔有如涓涓细流,絮絮叨叨,似耳语,似檐雨,叮叮咚咚,淅淅沥沥,似乎轻飘飘,软绵绵,却不知在何时,早已渗入你的内心,一阵感动。这就是张爱玲式的笔触,无孔不入,细而无声。
2015-05-31

看阿加莎作品的推理过程就像程序员追查一个“无法解决”的 Bug,没有找到根本问题之前,任何用户的描述都是值得怀疑的,靠掌握在手中的一点点线索,慢慢逼近事实真相,最后查出来的 Bug 往往与用户描述大相径庭,出人意料。
2015-06-11

想张恨水是比张爱玲的年代要更久远的作家,不自觉便把他同“很无趣的民国小说”绑在了一起。却没想到《秦淮世家》这部小说很出意料之外,写作手法很是新潮。
2015-06-17

即使不写作的读者,了解文学作品的写作技巧也是很有必要的。至少当你想说一部小说很好看的时候不会只有“太赞了”这样毫无信服力的词句,想批评一部小说很无聊的时候不会只有“一点不好看”这样纯粹主观的臆断。
本文为枫影夜读 #80 James Scott Bell — 《冲突与悬念》的附录:
2022-08-20 原《每周读书》系列更名为《枫影夜读》

每一个作家都希望自己的作品能够成为畅销作品,为大众所喜爱,“畅销”不一定有深度,但是受大家喜爱的作品一般都比较畅销。悬念小说作家James Scott Bell 针对“如何写出畅销小说”写了一系列写作指导书籍,《冲突与悬念》就是其中之一(可以参见 James 官网http://www.jamesscottbell.com/styled-7/index.html)。
作者认为写作技巧是可以传授的,不能传授的部分是作家本身的个人天赋、人生阅历、激情和胸怀,是这些作家自身的特质赋予了作品更为深刻的内涵,写作技巧则是承载这些内涵的必要工具。本书是针对“写作技巧”的指导,作者认为冲突与悬念是虚构小说最重要的两个元素,冲突是小说的引擎,而悬念则让小说形成张力,提供读者阅读下去的动力。
作者提倡以“内心的情感体验”为中心去写作,有点像互联网前两年流行的“以用户为中心的设计”,只不过互联网产品要赢得用户而小说是要赢得读者。
看完这本书,有两点是印象最为深刻的:
冲突与悬念对于虚构小说(尤其是重情节的推理小说、恐怖小说)来说确实是很重要的元素。 采用书中介绍的三幕剧结构,设置好两个重要的关口,第一个把主角推入主要情节无法回头,中间每一个场景都布置好悬念给予读者充足的阅读兴趣,然后第二个把主角推入最后决战,最后做一个精彩的收尾,这样一部小说从技巧上说是很吸引人的,读者也愿意读下去。这样看来很多网络小说都有这样的套路,同样技巧下作品能否赢取读者的内心就要看作者的内涵了。
文学作品常被拿来和音乐作品类比,被认为是主观而难以量化的。但正如音乐编写有各种既定的技巧,文学作品也如是。即使不写作的读者,了解文学作品的写作技巧也是很有必要的。至少当你想说一部小说很好看的时候不会只有“太赞了”这样空洞的形容,想批评一部小说很无聊的时候不会只有“一点不好看”这样纯粹主观的臆断。
James 的这本书英文原名是:Elements of Fiction Writing - Conflict and Suspense,中译本把主次标题对调了,如果读者对于这本书感兴趣,请千万一定要读英文原版,中国人民大学出版社的中译本翻译差强人意,读者虽然可以读懂大部分内容,却在一些关键点上差之千里。比如书中援引 Raymond Chandler 的话被翻译成:
唯恐天下不乱,乃作家职责所系,责无旁贷。
而事实上 Raymond Chandler 原话是这样的:
Trouble is my business.
这样意译未免有些过度。再比如讲冲突的第二节“为冲突展开头脑风暴”(Brainstorming for Conflict) 里,”An Image” 一节被翻译成“视觉画面”,但事实上这一节讲到了 Music, Dreams, Movie Mind,这里的 Image 翻译成“印象”或者“意象”要好得多,看到这里我都完全对不上关系还以为是漏印了什么内容。最可怕的是 Conflict in Theme 一章中:
Curly in City Slickers said the secret of life was “one thing.”
被翻译成了:
《城市滑头》中的克里曾说过:生活的秘密是“一个东西”。
当然我们可以说这本书里光是引用的电影和书名的翻译就得花上许多功夫,译者的困难是显而易见的。但是我想这并不能成为翻译质量低下的借口,这是译者本来就应该做的事情。尽管这本书的翻译多有不足,但至少让更多中文读者了解了写作指导类的书籍,这件事情本身是值得称赞的。
15.06.16/中午
于 T.i.T 创意园
《冲突与悬念》一书中提及的影视小说作品请参见此文:James Scott Bell 的《冲突与悬念》中提到的影视、文学作品
2022-08-20 原《每周读书》系列更名为《枫影夜读》

因着张爱玲这句“张恨水小说中的男主角”,对这男主角究竟是怎样颇为好奇。又想张恨水是比张爱玲的年代要更久远的作家,不自觉便把他同“很无趣的民国小说”绑在了一起。却没想到《秦淮世家》这部小说很出意料之外,写作手法很是新潮,悬念丛生,颇为吸引。
故事讲述了秦淮河上一户“歌女”人家与一个上海富商斗争的事情,男主角是在夫子庙摆书摊的穷书生徐亦进。形式上小说是旧式的章回体写法,手法上却很新潮,一开场就是歌女家的唐大嫂向邻桌“不认识的兄弟”打招呼,牵出“穷书生拾金不昧”之事,进而把这么一位刚正不阿读圣贤书之人,和“养娼妓”的人家联系到了一起,读者不由兴趣盎然:两种对立的人物碰撞到一起,能擦出什么样的火花来?
随后故事又引出有倾城容貌却颇为高傲的歌女唐小春,和“出淤泥而不染”的二小姐唐二春,男主角与二小姐的情意把男主角推进事件的漩涡,再无法抽离。随着故事的发展,男主角与唐家妈间处世哲学的对立,与二小姐的感情纠葛开始产生强烈的化学反应,这时候恶势力出现了,面对绑架与压迫,唐家嫂选择了逆来顺受,而性格激烈的二小姐与正直不屈的男主角则负隅顽抗,全书在与恶势力的终极对决中达到高潮。
在今天看来这个故事可能比较普通,然而作者却妙笔生花,每个章回都埋下一个悬念,牢牢抓住读者的眼球。但是到了小说后期,作者频频切换人物视角(POV),笔墨都着落在次要人物大狗和二春身上,让冲突的紧张感损失不少,一来失却了故事的紧张感,二来主角的戏份减少,让人不免有一种对人物的感情投资没有回报的失落之感。对于小说来说,这种失策是致命的,直接让读者没了一定要读的兴趣。
本是冲着“张恨水小说的男主角”这个印象去的,最后却发现男主角其实并没有什么戏份,连故事末最有象征意义的一把火都不是他点的,令人哭笑不得。故事倒是有些意境,恶势力的贼窝被烧毁之后,原地很快又新建起一栋高楼,原先为了躲开恶势力的唐小春回到秦淮河继续卖唱,太阳照样升起,地球一样转。主角们拼上性命的斗争,不过是秦淮河上一个小水花,淹没在岁月长河之中。
秦淮河上的女人,是离不开秦淮河的。
15.06.04
本文为 www.raywenderlich.com 上的一篇教程,由枫影翻译。
原文地址 http://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift

更新记录:本教程由 Richard Turton 针对 iOS 8, Xcode 6.1 和 Swift 进行了更新。原文由团队成员 Soheil Azarpour 编写。
相信大家都有过这样令人沮丧的经验:在 iOS/Mac 应用里按下一个按钮或者输入一些文字的时候,突然间整个界面就卡住不动了。
在 Mac 上,用户只能盯着那个彩色的球不停地转圈圈,好一会儿才能继续使用你的应用。在 iOS 上,用户则期望应用应该能实时地对自己的触摸动作进行反馈。这些不够流畅的应用看起来笨重而拖沓,一般都是差评如潮。
然而保持应用流畅度却是说起来容易做起来难。一旦你的应用需要执行繁重的任务,事情就会变得复杂起来。要在 Main Run Loop 里同时执行繁重的任务并且进行流畅的响应是不可能的事情。
一个可怜的开发者对此能做点什么呢?答案就是把繁重的任务从主线程挪到另一个并发的线程上。并发意味着你的应用可以同时多个操作流(或者线程)——以此达到界面响应用户输入的同时还能执行其他任务。
NSOperation 和 NSOperationQueue 是在 iOS 上实现并发操作的一种方法。在本教程中,你将会学习如何使用这些类。我们将从一个完全不使用并发的应用开始,这个应用会看起来很迟钝,然后你将对这个应用进行重构,加入并发操作让界面变得流畅起来!
本教程的示例工程主要用于展示一个 TableView,里面是加过滤镜的图片。图片要从网上下载下来,在本地加上滤镜效果,然后在展示在 TableView 里面。
下图是这个应用的模型:

请下载本教程的示例代码:http://cdn5.raywenderlich.com/wp-content/uploads/2014/10/ClassicPhotos-Starter63.zip
注意:所有的图片都来自stock.xchng。部分图片故意拼错名字,用于测试下载失败的情况
编译运行这个工程,然后(最终)你讲看到这个应用里展示了一个图片列表。试试看滚动一下这个列表,是不是菊花一紧?

所有的动作都在 ListViewController.swift 这个类里面,而且多数都写在 tableView(_:cellForRowAtIndexPath:) 方法里。
你会发现有两个操作是特别重的:
此外,应用刚开始还从网上下载了一份图片列表:
所有这些操作都是在主线程做的。由于主线程是用于更新UI,同用户交互的线程,阻塞了主线程就会让整个应用看起来很卡。你可以使用 Xcode 的 gauges view 查看应用的执行参数。

你可以看到 Thread 1 (也就是主线程)的 CPU 占用情况。如果想要查看应用的更多详情,你可以使用 Instruments,不过关于 Instruments 可以用一整篇文章来讲了。
OK,现在是时候进入优化部分了。
开始教程正文之前,这里有几个技术概念需要明确一下:
注意:在 iOS 和 OS X 中,多线程功能是由 POSIX Threads API(或者说 pthread)提供的,属于操作系统的一部分。这是一个比较底层的 API,很容易犯错,而且最糟糕的事这些错误是很难被察觉到的!
Foundation 框架里有一个类叫做 NSThread,相较而言要比底层接口好用多了,但是管理基于 NSThread 的多线程还是相当令人头疼。NSOperation 和 NSOperationQueue 则是更高级的类,提供更加简单的多线程管理接口。
下图中,你可以看到任务,线程和进程三者的关系:

可以看到,一个进程可以包含多个可以执行的线程,一个线程则可以同时执行多个人物。
在上图中,线程 2 执行读文件的操作,同时线程 1 则执行界面的展示工作。这跟 iOS 代码的结构很相似——主线程执行界面相关操作,子线程则负责耗时操作,比如读文件,网络操作等等。
你可能早已听过 Grand Central Dispatch (GCD) 的大名了。GCD 包含了语言特性,运行时库和系统优化,给 iOS 和 OS X 的并发和多核编程提供了一套系统而且强大的接口。想要了解更多关于 GCD 的内容,可以参考我们的文章:Multithreading and Grand Central Dispatch on iOS for Beginners Tutorial。
NSOperation 和 NSOperationQueue 是基于 GCD 之上的。一个通用的规则,苹果建议尽量使用最高级别的抽象接口,只有经过仔细权衡后觉得确实更底层的接口,才往下层走。
下面是一个 NSOperation 和 GCD 的一个简单的比较,便于你选择应该使用哪一种接口:
由于本文的示例中将对 Table View 进行优化,基于提高性能和减少功耗的考虑,你需要在一个图片 cell 被滚动出屏幕外的时候能够取消对这个图片正在执行的操作,所以我们将使用 NSOperation 来做这个优化。即使所有的操作都是在后台线程做的,如果有几十个耗时操作一直在后台队列中无法取消,对性能也是一种打击。
现在是时候完善一下那个没有多线程的应用模型了!如果你仔细观察这个一开始的模型,你会发现有三个地方可以被多线程优化。只要把这三个地方拆解到其他线程,主线程就可以减轻不少压力,提高流畅度。

为了突破应用的性能瓶颈,你将有一个主线程用于实时反馈用户输入,一个子线程专门用来下载图片,还有一个子线程用来对图片添加滤镜效果。在新的模型中,这个应用会从主线程启动,然后先加载一个空的 Table View。与此同时,应用将启动一个子线程用于下载数据源。
一旦数据源下载完,你将通知 Table View 进行 Reload。Reload Table View 是 UI 操作,所以一定要在主线程执行。在这时, Table View 就知道有多少行数据要进行展示,也知道每一行的图片对应的 URL。但是 Table View 还没拿到真正的图片数据!所以这个时候去下载所有图片是不明智的,你只需要看得到的那几张图片就可以了。
这里有什么可以优化的点呢?
一个更好的模型是,只下载显示在屏幕上的那几张图片。所以你的代码首先要问 Table View 要能看到的那些行,然后开始下载的工作。同时,滤镜线程在没有真实图片之前也无法开始工作。所以,在图片还没有下载完之前,滤镜线程不应该被启动。
要让应用看起来更流畅,你的代码应该要能在图片下载完就立刻显示出来。然后再启动滤镜线程,等滤镜加载完毕再更新 UI 显示添加过滤镜的图片。下面这个图片展示了完整的流程:

为了达成这些目标,你首先需要跟踪正在下载、已经下载完的图片,还要知道图片是否已经加过滤镜了。然后你还需要跟踪每一个操作的状态,以便在用户滚动界面时可以取消、暂停或者继续之前的操作。
Okay!现在我们已经准备好开始写代码了!:]
打开示例工程,添加一个新的 Swift 文件,名为:PhotoOperations.swift。添加以下代码:
// This enum contains all the possible states a photo record can be in
enum PhotoRecordState {
case New, Downloaded, Filtered, Failed
}
class PhotoRecord {
let name:String
let url:NSURL
var state = PhotoRecordState.New
var image = UIImage(named: "Placeholder")
init(name:String, url:NSURL) {
self.name = name
self.url = url
}
}
[/sourcecode]
注意:请确保 import UIKit 这句在文件的顶部。默认情况下,Xcode 会帮你引入 Foundation 文件的。
这个简单的类将代表每一个展示在应用里的图片,同时包含图片的状态(初始状态为 .New)。图片默认是一张占位图。
为了追踪每一个操作的状态,你需要另一个类。把下面这个类的定义加到 PhotoOperations.swift 底部:
lazy var filtrationsInProgress = [NSIndexPath:NSOperation]()
lazy var filtrationQueue:NSOperationQueue = {
var queue = NSOperationQueue()
queue.name = "Image Filtration queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
}
[/sourcecode]
这个类包含了两个 Dictionary,用来追踪 Table View 里每一行的下载和滤镜状态,同时还有两个 Operation Queue 用于图片下载和滤镜操作管理。
所有的值都被声明为 lazy create,也就是说只有等到第一次用到这个值它才会真正被初始化。这也将是应用的性能得到提升。
创建一个 NSOperationQueue 也是挺直观的。给 NSOperationQueue 命名是很有用的,这个名字会在 Instruments 或者 debugger 里面显示出来。出于本文的教学目的,这里最大并发数 maxConcurrentOperationCount 被设为 1,这样你可以清楚地看到这些操作一个接一个地往下走。你也可以改成让队列本身去决定最大并发数,这将更大地提升你的应用性能。
那么队列本身是怎么决定最大并发数的呢?好问题!:]这是由硬件来决定的。默认情况下,NSOperationQueue 会自己计算出对当前平台来说最好的决策,然后启动尽可能多的线程。
试想一下下面这个例子。假设这时候系统出于空闲状态,有很多可用资源,那么这个队列可能会启动大概 8 个并发线程。下一次你启动这个 App 的时候,有可能系统正在处理其他操作,那这个队列可能就只有 2 个并发线程。在这个示例工程里,由于你设置了最大并发数为 1,所以同时只会有一个操作在执行。
注意:你可能觉得奇怪,为什么我们要跟踪所有下载中和等待下载的操作,队列本身有一个 operations 属性可以返回所有操作,为什么不直接用这个就好了?在这个项目中,这么做可能不太高效。因为你必须把 table view 的行数和操作关联起来,这么做意味着你每次都要循环一遍整个数组去查找属于哪一行,使用 Dictionary 把 indexPath 作为 Key 存起来则可以很快地找到对应的操作。
接下来我们要对下载和滤镜操作进行管理了。把下面这些代码加到 PhotoOperations.swift 文件底部:
//2
init(photoRecord: PhotoRecord) {
self.photoRecord = photoRecord
}
//3
override func main() {
//4
if self.cancelled {
return
}
//5
let imageData = NSData(contentsOfURL:self.photoRecord.url)
//6
if self.cancelled {
return
}
//7
if imageData?.length > 0 {
self.photoRecord.image = UIImage(data:imageData!)
self.photoRecord.state = .Downloaded
}
else
{
self.photoRecord.state = .Failed
self.photoRecord.image = UIImage(named: "Failed")
}
}
}
[/sourcecode]
NSOperation 是一个抽象类,是为了继承而设计的。每一个子类代表一个特殊的任务(如前所述)。
上面代码里各行注释的含义如下:
接下来,你需要创建另一个 Operation,用于执行滤镜操作!把下面代码添加到 PhotoOperations.swift 文件里:
init(photoRecord: PhotoRecord) {
self.photoRecord = photoRecord
}
override func main () {
if self.cancelled {
return
}
if self.photoRecord.state != .Downloaded {
return
}
if let filteredImage = self.applySepiaFilter(self.photoRecord.image!) {
self.photoRecord.image = filteredImage
self.photoRecord.state = .Filtered
}
}
}
[/sourcecode]
这个看上去很像下载 Operation,只是用图片添加滤镜(这里用了一个还没实现的函数,所以会有一个编译错误)代替了下载操作。
下面我们给 ImageFiltration 类添加图片滤镜操作的代码:
if self.cancelled {
return nil
}
let context = CIContext(options:nil)
let filter = CIFilter(name:"CISepiaTone")
filter.setValue(inputImage, forKey: kCIInputImageKey)
filter.setValue(0.8, forKey: "inputIntensity")
let outputImage = filter.outputImage
if self.cancelled {
return nil
}
let outImage = context.createCGImage(outputImage, fromRect: outputImage.extent())
let returnImage = UIImage(CGImage: outImage)
return returnImage
}
[/sourcecode]
这里的滤镜实现跟之前 ListViewController 中的实现是一样的,只是搬到了一个 Operation,从而可以在后台执行这个操作。同样的,你还是要经常检查任务是否已经被取消了,最佳实践是在耗时操作之前和之后各检查一次。一旦滤镜添加完成,你就可以设置 photo record 的状态了。
牛逼!现在你已经拥有执行后台任务的所有必备工具了,是时候回到 View Controller 中修改你的旧代码了。
回到 ListViewController.swift 文件,删掉 lazy var photos 声明,添加下面的声明:
如此你将有一个照片对象的数组和一个等待任务的队列。
下面我们添加一个新的方法用于下载图片信息的 plist 文件。
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {response,data,error in
if data != nil {
let datasourceDictionary = NSPropertyListSerialization.propertyListWithData(data, options: Int(NSPropertyListMutabilityOptions.Immutable.rawValue), format: nil, error: nil) as! NSDictionary
for(key : AnyObject,value : AnyObject) in datasourceDictionary {
let name = key as? String
let url = NSURL(string:value as? String ?? "")
if name != nil && url != nil {
let photoRecord = PhotoRecord(name:name!, url:url!)
self.photos.append(photoRecord)
}
}
self.tableView.reloadData()
}
if error != nil {
let alert = UIAlertView(title:"Oops!",message:error.localizedDescription, delegate:nil, cancelButtonTitle:"OK")
alert.show()
}
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
}
[/sourcecode]
这个方法创建了一个异步的网络请求,请求结束后在主线程回调。文件下载后会被解析成一个 NSDictionary 对象,然后再解出来一个 PhotoRecord 数组。这里你不会直接使用到 NSOperation,而是用到主队列 NSOperationQueue.mainQueue()。
在 ViewDidLoad 方法中调用这个下载函数。
接下来,找到 tableView(_:cellForRowAtIndexPath:) 然后替换成下面的实现:
//1
if cell.accessoryView == nil {
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .Gray)
cell.accessoryView = indicator
}
let indicator = cell.accessoryView as! UIActivityIndicatorView
//2
let photoDetails = photos[indexPath.row]
//3
cell.textLabel?.text = photoDetails.name
cell.imageView?.image = photoDetails.image
//4
switch (photoDetails.state){
case .Filtered:
indicator.stopAnimating()
case .Failed:
indicator.stopAnimating()
cell.textLabel?.text = "Failed to load"
case .New, .Downloaded:
indicator.startAnimating()
self.startOperationsForPhotoRecord(photoDetails,indexPath:indexPath)
}
return cell
}
[/sourcecode]
请花点时间通读一下下面的注释详解:
现在你可以把 ViewController 里面的 applySepiaFilter 删掉了,添加以下代码,用于启动一个 Operation:
这里,你将把一个 PhotoRecord 和 IndexPath 作为参数传入,基于图片的状态,你可以选择启动下载或者滤镜 Operation。
注意:用来下载和添加滤镜的方法是分开实现的,有可能有些图片已经下载完了,然后被滚出屏幕外了,这时候图片滤镜还没加上。所以下一次用户滚动到同一行的时候,你不需要重新下载图片,只要加上滤镜就行了!牛逼烘烘!:]
现在你要实现上面调用到的方法了。还记住你创建了一个自定义的类PendingOperations 用来跟踪 operation吗?现在你可以用上这个类了!添加下面的代码:
//2
let downloader = ImageDownloader(photoRecord: photoDetails)
//3
downloader.completionBlock = {
if downloader.cancelled {
return
}
dispatch_async(dispatch_get_main_queue(), {
self.pendingOperations.downloadsInProgress.removeValueForKey(indexPath)
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
})
}
//4
pendingOperations.downloadsInProgress[indexPath] = downloader
//5
pendingOperations.downloadQueue.addOperation(downloader)
}
func startFiltrationForRecord(photoDetails: PhotoRecord, indexPath: NSIndexPath){
if let filterOperation = pendingOperations.filtrationsInProgress[indexPath]{
return
}
let filterer = ImageFiltration(photoRecord: photoDetails)
filterer.completionBlock = {
if filterer.cancelled {
return
}
dispatch_async(dispatch_get_main_queue(), {
self.pendingOperations.filtrationsInProgress.removeValueForKey(indexPath)
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
})
}
pendingOperations.filtrationsInProgress[indexPath] = filterer
pendingOperations.filtrationQueue.addOperation(filterer)
}
[/sourcecode]
Okay! 下面这个列表会告诉你这段代码干了些啥:
给图片添加滤镜的操作也是一样的模式,除了使用 ImageFiltration 和 filtrationsInProgress 来追踪任务之外。作为练习,你可以自己尝试重构这部分代码,提取重用部分 :]
最后,你成功了!现在你的工程已经完整了。编译运行一下看看!现在滚动列表将不再卡顿,App 在看得见图片的时候才开始下载和添加滤镜,体验流畅无比!

这难道不是很酷吗?你可以看到小小的努力可以让你的应用变得更加流畅——用户将获得更多乐趣!
能看到这里已经很不容易了!你已经让这个项目优化了许多。但是,我们还是有一些细节可以进行调整。你想要的是变成一个伟大的程序员,而不只是一个好程序员。( You want to be a great programmer, not just a good one!)
也可能已经注意到当你滚动列表把图片滚出屏幕外的时候,那些任务还在不停地下载和添加滤镜。如果你滚得很快,队列将被塞满,滚到底部的时候那些图片要等很久才能出现。理想情况下,我们应该取消那些不在屏幕里的任务。
你不是已经添加了“取消”的代码了吗?现在是时候用上他们了!:]
回到 Xcode,打开 ListViewController.swift。找到 tableView(_:cellForRowAtIndexPath:) 的实现,给 startOperationsForPhotoRecord 的调用包上一个条件判断:
这里你让 Table View 只在不滚动的时候才开始下载。这两个属性其实是 UIScrollView 的属性,UITableView 是 UIScrollView 的子类所以可以直接用。
接下来,要实现 UIScrollView 的 Delegate 方法:
override func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
// 2
if !decelerate {
loadImagesForOnscreenCells()
resumeAllOperations()
}
}
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
// 3
loadImagesForOnscreenCells()
resumeAllOperations()
}
[/sourcecode]
这段代码做了这么件事:
现在,我们把漏掉的实现加回 ListViewController.swift 文件中:
func resumeAllOperations () {
pendingOperations.downloadQueue.suspended = false
pendingOperations.filtrationQueue.suspended = false
}
func loadImagesForOnscreenCells () {
//1
if let pathsArray = tableView.indexPathsForVisibleRows() {
//2
var allPendingOperations = Set(pendingOperations.downloadsInProgress.keys.array)
allPendingOperations.unionInPlace(pendingOperations.filtrationsInProgress.keys.array)
//3
var toBeCancelled = allPendingOperations
let visiblePaths = Set(pathsArray as! [NSIndexPath])
toBeCancelled.subtractInPlace(visiblePaths)
//4
var toBeStarted = visiblePaths
toBeStarted.subtractInPlace(allPendingOperations)
// 5
for indexPath in toBeCancelled {
if let pendingDownload = pendingOperations.downloadsInProgress[indexPath] {
pendingDownload.cancel()
}
pendingOperations.downloadsInProgress.removeValueForKey(indexPath)
if let pendingFiltration = pendingOperations.filtrationsInProgress[indexPath] {
pendingFiltration.cancel()
}
pendingOperations.filtrationsInProgress.removeValueForKey(indexPath)
}
// 6
for indexPath in toBeStarted {
let indexPath = indexPath as NSIndexPath
let recordToProcess = self.photos[indexPath.row]
startOperationsForPhotoRecord(recordToProcess, indexPath: indexPath)
}
}
}
[/sourcecode]
suspendAllOperations 和 resumeAllOperations 的实现都很直观了。NSOperationQueues 是可以被挂起的,设置 suspended 为 true 就行了。这样整个队列里所有的任务都会被挂起——你没有办法只挂起单个任务。
loadImagesForOnscreenCells 稍微复杂一点:
编译运行一下,现在你应该有一个更加流畅,资源管理更加合理的应用了!你们的掌声在哪里!

注意到现在只要你停止滚动 Table View,当前屏幕上的 Cell 就会立刻开始下载了。
这里有一个完整的项目工程可供大家下载。
如果你已经完成了这个项目而且确实花时间理解了所有的东西,那么恭喜你!相比你刚开始看这篇文章,你已经是一个更有价值的 iOS 开发者了!多数开发团队都会为拥有一个或两个真正懂得这些东西的开发者而感到幸运。
但是要注意——就像多层嵌套的 block 一样,无理由地滥用多线程也会让你的代码变得难以维护。多线程可能会引入很多难以察觉的bug,只在网络差的时候,设备性能特别好的时候,或者跟你写代码的机器的 CPU 数不一样的时候才会出现。你必须很小心地测试这些代码,经常使用 Instruments(或者你自己喜欢的工具)来确认引入多线程确实让性能得到了提高。
这篇文章里没有提到,Operation 还有一个很有用的特性,就是依赖(dependency)。你可以创建一个依赖于其他 Operation 的 Operation。这个 Operation 只有在那个依赖的 Operation 全部执行完了它才会启动。举个例子:
filterOperation.addDependency(downloadOperation)
[/sourcecode]
要解除依赖关系只要一句代码:
如果用上依赖关系,是否可以简化本文介绍的这个工程呢?你可以用上这个新技能自己试一下 :] 值得注意的是,有依赖关系的 Operation 即使被依赖的 Operation 被取消了,它也依然会被启动,你需要随时牢记这一点。
2022-08-20 原《每周读书》系列更名为《枫影夜读》

还在念书时曾在学校的书店里多次见过《东方快车谋杀案》的封皮,却一直记不住作者的名字。这周末因缘际会,竟一口气读了她三部小说,心中颇感敬佩。
提到英国的侦探小说就不得不提柯南道尔,笔下的福尔摩斯比作家有名的人物,阿加莎克里斯蒂便是与他齐名的侦探小说家,笔下也有波罗侦探与马普尔小姐这样的系列人物。兴许与她创作的时间在 1920——1976 这段时间有关,枫影对这位“侦探小说女王”并不十分熟悉,然而读完《悬崖山庄奇案》,已被其精妙的情节构思所吸引。阿加莎是一位高产的作家,创作生涯几乎每年都有一到两部作品出版,留下的小说作品也有百余部之多。于是枫影又读了同属“波罗侦探系列“”的代表作:《罗杰疑案》与《东方快车谋杀案》。
这三部作品都不算薄,读起来却奇快。阿加莎几乎没用一点高级修饰,人物对话也几乎不描述动作与表情,写作手法更是几乎都一个套路:开场人物——案件发生——推理过程——揭开谜底,但是由于情节设计极为巧妙,小说的结局总能有惊人的反转。至于翻译质量,得益于阿加莎通俗易懂的语言风格,新星出版社出版的这几部作品可读性都极佳,我相信还没读到的其他作品也是一样的。
如果说东野圭吾的推理作品如新世纪福音战士,带有深刻的人性挖掘和阴暗的社会背景,那么阿加莎的作品就是哆啦A梦,有着巧妙的情节编排和明快的抒写笔调。推理小说是强调情节设计的文体,然而东野圭吾的小说却寄予了超出推理本身的深层寓意,比如《白夜行》,是社会的阴暗导致了主角人格扭曲,行事邪恶,唯有心中的爱才是真诚,又比如《嫌疑犯x的献身》,除了推理情节上石神与伽利略的精彩角力之外,更充满了法律与公正的冲突,罪恶与现实的无奈,到头来谁才是真正的残忍,让故事本身超出了侦探小说的属性。
反观阿加莎的作品,她并没有给笔下的故事注入太多沉重的现实,波罗只是个自命不凡矮个子名侦探,他拥有的武器就是他冷静的推理能力,他的凶手都是乖乖呆在那里等着他非凡的推理结束后揭露出来的,没有凶险的抗争也没有血腥的一面(真要有的话波罗应该牺牲很多次了),只靠她精妙的情节设计,让读者拍手叫好。
我想这种语言平易近人,情节扑朔迷离的特色正是其畅销的原因。她喜欢在作品中铺陈所有已知的证据,侦探迷们大可自行推理还原事实真相,再往后读加以验证,而懒人如我则可直接跃进到结局,看大侦探召集所有人宣布推理结果,感受反转结局的魅力。东野的作品由于其附加属性往往较为沉重,有些作品如《嫌疑犯x的献身》可以再看一遍感受内心的震动。而阿加莎的作品则更像如茶余饭后的闲适读物,长途旅行备上一本最好打发时间,一旦解开谜底就不会再看第二遍了。
15.05.31/夜
于自居
