文章目錄
  1. 1. Swift
    1. 1.1. Swift 与后端开发
  2. 2. 准备春招
    1. 2.1. 图解 TCP/IP
    2. 2.2. 剑指 Offer
    3. 2.3. iOS
  3. 3. 入职
    1. 3.1. MVC 与 UITableview
    2. 3.2. 高效使用 Mac
  4. 4. iOS 深入
    1. 4.1. GCD 与多线程
    2. 4.2. Runloop
    3. 4.3. 线程调用栈
    4. 4.4.
    5. 4.5. Xcode 项目配置
  5. 5. 全栈
    1. 5.1. 哈希表
    2. 5.2. Node.js
    3. 5.3. 前后端分离与前端开发流程
    4. 5.4. 利用 JS 等脚本语言实现客户端热更新
    5. 5.5. 脚本语言
    6. 5.6. 面向接口编程
    7. 5.7. 安卓
  6. 6. 我的 2016
  7. 7. 2017 年的计划

时光飞逝,一转眼已经是一年过去了, 去年的今天我写下了第一篇年度总结:一个普通iOS开发者的2015大总结。在写作那篇文章之前,我觉得一年前的自己完全是一个傻逼;今天重读一遍以后,我感觉一年前的自己也非常傻逼。在写下这一年总结的同时,我也希望明年的自己在回顾这篇文章的时候,可以发出不屑的鄙视。

实际上我认为:

刚开始学习的前五年是发展最快的五年,每一年都应该感觉到自己在过去的一年中发生了天翻地覆的变化。

本文既然是总结, 自然是充满了大量的主观看法。如果读者不认可其中的某些观点,大可呵呵一笑,抛之脑后,切勿较真,做无意义的争论。

Swift

我从元旦后就开始着手准备春招。首先翻译完了 Advanced Swift(盗版可耻),这是自己第一次完整的阅读完一本英语书籍,学到了非常多的知识,有英语方面的,也有 Swift 方面的,随后自己尝试着用 Swift 开发了一个小 app。虽然后续由于工作原因没有能继续接触 Swift,不过它的优雅、简洁还是深深的吸引了我。希望 Swift 4.0 发布后能够解决 ABI 稳定问题。

如果 Xcode 对 Swift 的支持能更友好,业内再提出成熟的动态化方案,我相信 Swift 会有更光明的未来和使用场景。

Swift 与后端开发

随着 Swift 的愈发成熟,业内出现了很多比较成熟的后端开发框架, 比如 perfectvapor 等。然而我本人并不看好这一领域,主要是从编程语言和程序员两个角度出发。

理论上来说,任何可以调用 socket 接口处理网络请求的语言都可以用来做后端开发,然而对于 Swift 来说,除了处理网络请求以外,一个优秀的 API 也至关重要。不管是 HTTP 协议的解析,还是字符串、栈、时间等常用数据结构的操作,都不方便由做业务的程序员去手动解析。

框架的使用者应该关注业务开发,而不是通用业务的处理。比较遗憾的是,Swift 目前在这一方面做的还不够好,很多重要的操作缺乏语言层面的支持,导致开发者造轮子的成本过高。不过 Swift 已经成立了官方小组,致力于解决这一问题。

考虑到 Swift 还不是个非常成熟的语言,目前还在快速迭代。相比于语言本身,我认为人的问题才是阻碍 Swift 在服务端发力的最大原因。不管是现有哪种用来进行后端开发的语言,都有它本身的卖点。比如 Java 的高效(运行时效率)、稳定、全面,或者 PHP、Ruby 的语法简洁,易上手,还是 GO 的高并发,亦或是 Node.js 的全栈,都能在某个特定场景下派上用场。

目前的 Swift 似乎还没有找到属于自己的舞台,由于绝大多数开发者都是 iOS 开发者,他们并不适合转向服务端开发,这就意味着 Swift 能写 iOS 毫无吸引力(参考一下 JS 能做哪些事)。而对于具有服务的开发经验的开发者来说,Swift 又没有吸引他们切换过去的理由。

准备春招

一不小心就扯远了, 话题回到总结上来。完成了 Swift 学习的收尾工作后,我的精力主要放在春招上。由于大二下学期积累了三个月的实习经验,这一阶段的目的主要是夯实基础。因此重点读了两本书,《图解 TCP/IP》(总结)、《剑指 Offer》。

图解 TCP/IP

这本书主要是讲解了 TCP/IP 四层协议栈(或者分得更细点就是七层),通过一些插图和实际例子来解释枯燥的概念。我认为这是一本不可多得的好书,尤其适合新手入门。不过,如果想精通网络层,还是建议买 《TCP/IP 详解》和 《HTTP 权威指南》或者直接查阅 RFC 协议。

不过在准备面试,或者新手入门时,我觉得非常有必要通过一本简短的书籍来形成大致的知识框架和,这样后续才能有针对性的学习总结,对自己的知识框架进行各种修修补补。

剑指 Offer

这本书相当应试,不过也必须承认它概括了绝大多数常见的算法面试题。如果我们把面试看做是企业对应聘者的能力筛选和鉴定而不是刁难,那么从一定角度来说,也可以证明这本书涵盖了绝大多数常见的场景和算法。

如果不想只是纸上谈兵,还可以去 Leetcode 上找找书中问题对应的题目,参考全世界大牛的精妙解法也会受益匪浅。

iOS

作为一名 iOS 开发者,iOS 开发是我的本业,除了准备计算机基础知识外,我也学习了很多 iOS 开发的知识。以上的详细内容都总结在 《让 BAT 的 Offer 不再难拿》,就不赘述了。

入职

春招顺利的拿到了百度贴吧的 offer,入职以后受益匪浅。在善品、权叔等老司机的带领下,我有一种乡下人进城的兴奋感,感觉自己的成长速度非常快。

MVC 与 UITableview

UITableview 是 iOS 开发中最常见的 UI 控件之一,但是想写好一个 UITableview,做到封装、解耦,并与网络请求良好的结合起来并不容易。我花了一定时间学习了贴吧以前的框架,对其做了一些简化和整理,总结在这里: 如何写好一个UITableView。框架没有最优与全能,适合团队业务的就是最好的,所以这套框架主要是为了贴吧业务打造,但也有自己的不足,读者切不可照搬全抄。

高效使用 Mac

我比较看重开发效率,因为我认为开发者应该把宝贵的时间花费在工作本身,而不是与之无关的杂事上。并不耗时的高频操作和比较耗时的中频操作都应该使用快捷键或自动化工具对其进行简化,不过也切忌矫枉过正。对非常低频的操作进行自动化或者仅仅是为了装逼,往往会浪费大量不必要的时间,反而适得其反。

我总结了一篇文章 并做了一次直播,主要涉及全局快捷键、Xcode、Vim、Chrome、Vimium、Git、Zsh、Alfred、Zsh、Emacs 等. 强烈建议对此还不了解的读者收看直播回放。

iOS 深入

在工作之余,我对 iOS 领域的一些常用知识做了深入学习。

GCD 与多线程

虽然去年就复习过类似的话题,但仅仅是停留在总结整理的层面,说白了就是把所有 API 熟悉了一遍。这次学习时,我阅读了 GCD 的源码,从而从更深层次理解了 GCD 的实现原理,总结了一篇文章: 深入理解 GCD

Runloop

最初接触 runloop 是听了孙源大神的分享,随着学习的深入,发现还是有必要对 Runloop 进行深入的理解。不过 Runloop 虽然重要,但实际使用中接触得并不太多,除了常见的 NSTimer 触发问题外,也就是性能检测时会与之打交道。所以它源码阅读的必要性并不是太高,我觉得只要对 Runloop 的基本概念和工作原理有所涉猎即可。遇到实际问题时可以查阅 ibireme 的 深入理解RunLoop

我写了一篇: 深入研究 Runloop 与线程保活 作为自己的学习总结。

线程调用栈

上一节谈到了利用 runloop 检测主线程的卡顿。为了找到性能瓶颈,也就是优化点,我们需要在卡顿发生时得到实时的线程调用栈。这就意味着一切依赖于线程层面的操作都会破坏原来线程的调用栈。在尝试使用信号无果后,最终我选择了参考第三方开源框架,直接利用 C 语言解析函数调用栈。具体总结参考: 获取任意线程调用栈的那些事

iOS 中有很多锁,从最底层的互斥锁、信号量到顶层的 @synchronized,应有尽有。虽然我实际使用经验并不多,但还是研究了一下他们的实现原理和性能优劣: 深入理解 iOS 开发中的锁。随着对多线程在理论和实践上的进一步接触,我相信还会有更具深度的总结面世。

Xcode 项目配置

出于对 Cocoapods 工作原理的兴趣,我前段时间手动模拟了它的工作过程(自动化是通过 ruby 脚本完成的,相对而言重要性低很多)。在这一过程中,更重要的是对编译、链接、Xcode 工程配置的理解。由于时间原因,目前还没有形成总结性文档。

全栈

相比于 iOS 方面的钻研,2016 年最让我感到激动和收益满满的是横向的拓展。关于为什么会选择横向发展路线,在我的 新的开始 一文中已经有了详细的阐述。

哈希表

哈希表是常见的数据结构,但是很多人对他的掌握都非常浅显。曾经问过很多人一个很简单的问题:“为什么很多哈希表的实现中,数组的长度都是 2 的整数次幂?”。根据我的观察,能答出这个问题的人寥寥无几,有很多看上去很正确的废话,其实恰恰说明了大多数人多哈希表的理解还不够深入。

除此以外,不同的语言和框架(OC、Java、Redis、一致性哈希) 对哈希表的实现都各不相同,他们的取舍恰恰说明不同场景下我们关注的指标并不一致,必须舍弃一些无关紧要的功能点,来换取主要功能的性能的大幅度提高。具体对比请参考: 深入理解哈希表

Node.js

市面上有很多介绍 Node.js 的优秀文章和书籍,作为一个不懂 Node.js 的小白,其实我只关系以下几个问题:

  1. 为什么要从现有的后端开发框架切换到 Node.js?
  2. Node.js 是银弹么,还是有特别适合自己的使用场景?
  3. Node.js 的事件循环是如何工作的?有什么好处?
  4. Node.js 是异步单线程的, 那么如何最大程度的利用多核 CPU 的所有性能?

作为上述问题的回答,我总结了 为什么要用 Node.js

前后端分离与前端开发流程

在学习 Node.js 的过程中,我接触到了一个新名词:前后端分离。对于客户端开发者来说,前后端分离是一件天经地义的事情。前端界面是由编译后的代码生成的,相对来说比较固定。前后端的主要交流方式是 JSON/protobuf 等数据交换格式。

然而对于前端开发者来说,事情远远不止这么简单。由于前端的 UI 样式完全由 Server 下发,所以很容易就产生了前后端业务和代码的耦合。所以前后端分离说的就是前端开发和后端开发如何进行解耦和数据交互,详见 移动端开发者眼中的前端开发流程变迁与前后端分离

利用 JS 等脚本语言实现客户端热更新

不管是 JSPatch 还是 React Native,它们都能做到客户端的热更新,甚至无需通过 AppStore 即可发一个新版本。它们之所以能够做到客户端热更新,主要是依赖了客户端对 JavaScript 的支持以及 iOS 自身基于 runtime 的元编程技术。首先,利用 JSON 传递信息的区别在于它仅有描述信息,却无法携带逻辑信息。

通过官方认可的 JavaScriptCore 框架,我们可以运行一段 JavaScript 代码并获取运行结果。通过对运行结果的解析,我们可以利用 runtime 动态的调用本地预定义好的方法,从而实现了动态化。

React Native 的本质是一个 Hybrid 桥。它与 React 具有相同的 API,为了实现相同的效果,客户端会调用本地的方法(比如 addSubview 等)。详细请参考: React Native 从入门到原理

脚本语言

一般来说我们认为脚本语言就是没有编译器的、由解释器动态解释的语言。它通常具有弱类型、格式简单、开发效率高等优点,但是作为代价,用脚本语言来开发大型项目会遇到诸多问题。比如性能、调试等等,毕竟它们原本只是用来快速完成某个小的需求。

我最先接触的是 python,我使用 python 编写了 alfred 的一个 workflow,后来在 leader 的带领下实现了一个可以 hook 请求和返回结果的 http 代理服务器。有了实战的机会,也就成功脱离了 hello world 的水平了。

同时我也简单接触了 Ruby。光从脚本语言的角度来看,它和 Python 的作用相仿。不过很多领域特定语言(DSL) 都选择了 Ruby 来实现, 比如我们常用的 cocoapods 中的 Podfile,如果不说,可能只有少数人能意识到这其实是一段标准的 Ruby 代码。

之所以选择用 Ruby 来实现,是因为它的语法可读性更好,看上去就像一段普通的描述性文字。详细的分析可以参考: 白话 Ruby 与 DSL 以及在 iOS 开发中的运用

严格意义上来说,Shell 脚本才是脚本语言的鼻祖,它提供了非常多常用的工具,比如 awksed 两大文本处理利器。如果需要对文字、文件目录做简单的逻辑操作,应该优先使用 Shell 而不是其他脚本语言。

不同的脚本语言往往是为了解决不同领域的问题而诞生的(虽然它们也可以解决其他问题),遇到问题的时候应该选择最合适、优雅的解决方案,而不是总想着复用当前技术栈。俗话说:“如果你只有锤头,那看什么都是钉子”。

面向接口编程

Swift 诞生后就一直宣传自己面向接口编程的特性,然而在我看来它不过是一种多继承的实现方案。且不谈继承的缺点以及在它和组合之间如何选择,光是多继承,就有很多种实现。比如 C++、Python、Java、Ruby 都有各自的实现。其中有优雅的,也有相对来说比较暴力直接的。

我个人更喜欢 Java 对多继承的实现,与之相比,Swift 的面向接口编程还有一些可以提高的地方。详细可以参考: 从 Swift 的面向协议编程说开去

安卓

从 12 月份开始,由于安卓同事返校上课,我有机会开始接触安卓开发。目前还停留在小白阶段,只能根据前人的代码抄抄改改。安卓的学习主要还是 API 的积累和 Java 语言的学习,希望能在明年总结出更多关于安卓的优秀文章。

我的 2016

对于把好好的年终总结写成了博客摘要我是很不满意的,如果用一个词来总结我的 2016 年,我想那毫无疑问就是:“拓宽”。虽然 iOS 还没有达到炉火纯青的地步,但我还是义无反顾的开始了横向拓宽。我相信一个人才的最大价值,不是做好某一个具体的小需求(这是前提),而是站在更高的角度做更大的事。

16 年技术栈拓展中,最大的三个收获应该是前端、Python 和安卓。然而考虑到与工作相结合,我想前端技术暂时可以放一放,重点学习 Python 和安卓也许会对 KPI 更加有利。

当然,好的书还是要读的。博客可以解释清楚某一个问题,而好书可以解释清楚某一个领域。在 Server 方面,李智慧的 《大型网站技术架构》 可以算作一本非常优秀的入门版书籍,介绍了诸多常见的属于和概念。而《计算机程序的构造和解释》(SICP) 作为 MIT 几十年来的教科书,是一本非常经典的介绍函数式编程的书籍。以上两本书推荐给感兴趣的读者。

过去的这一年成长了很多,从简书、微博几十个粉丝的小菜鸟,到几千粉丝的小 V,一路走来收获满满。不过我逐渐意识到越是大型的平台,普通用户的质量就越接近于行业平均水平。因此粉丝数、喜欢数并不值得参考,而且很多交流其实是浪费时间。因此在新的一年中我会减少社交平台上的互动,把有限的精力投入到线下的生活、工作、学习中去。

2017 年的计划

在去年的年终总结里,我列出了五点计划:

  1. 继续翻译优秀的英文文章。这一点做的不太好,虽然有幸加入了 SwiftGG 并翻译了一些 Swift 文章,但是总的来说数量还不够。不过考虑到还有非常多要做的事,翻译文章的性价比似乎就不太高了,所以暂时搁浅。
  2. 阅读优秀的博文。objc.cn 的文章在带着读,由于掌握了 Google 搜索, 所以再也不会像去年一样看 CSDN 了,从这一点来说,第二个目标算是圆满完成。
  3. 技术与基础。今年学习了 GCD、Runloop、Runtime、锁、Cocoapods、React Native 等技术,算是加深了技术深度,
  4. 读书。读完了 《图解 TCP/IP 》、《剑指 Offer》、《大型网站技术架构》、《计算机程序的构造与解释》,双十一还买(挖)了不少书(坑)。
  5. 实习。在贴吧和凤巢的日子里,小组里的各位同事一直在帮助我成长,我的每一丝进步都要感谢他们的帮助。

总的来说 16 年的计划圆满完成了,在新的一年里我为自己制定了几个小目标:

  1. 业务: 也许业务没有技术重要,但是没有业务的积累,再厉害的技术也只会浪费时间,甚至带来负面作用。踏入工作岗位后,我希望在 2017 年更加深入的理解团队业务,更好的融入团队的交流协作中。
  2. 读书: 双十一买了十几本书,目前看来优先级最高的是《七周七并发模型》和 《改善 Python 程序的 91 个建议》,如果有空的话 《Java 编程思想》和 《Effective Java》、《Android 开发艺术探索》也在计划中。
  3. 技术: 所谓的全栈工程师,或者 T 型人才并不是全干工程师,每一门技术必须掌握到一定深度。因此在跨界时切忌自我麻痹,不能总以“我是新手”为理由来安慰自己。我希望在新的一年里在 Python 和 Android 方面达到一定深度,以工作为标准来要求自己。
文章目錄
  1. 1. Swift
    1. 1.1. Swift 与后端开发
  2. 2. 准备春招
    1. 2.1. 图解 TCP/IP
    2. 2.2. 剑指 Offer
    3. 2.3. iOS
  3. 3. 入职
    1. 3.1. MVC 与 UITableview
    2. 3.2. 高效使用 Mac
  4. 4. iOS 深入
    1. 4.1. GCD 与多线程
    2. 4.2. Runloop
    3. 4.3. 线程调用栈
    4. 4.4.
    5. 4.5. Xcode 项目配置
  5. 5. 全栈
    1. 5.1. 哈希表
    2. 5.2. Node.js
    3. 5.3. 前后端分离与前端开发流程
    4. 5.4. 利用 JS 等脚本语言实现客户端热更新
    5. 5.5. 脚本语言
    6. 5.6. 面向接口编程
    7. 5.7. 安卓
  6. 6. 我的 2016
  7. 7. 2017 年的计划
Fork me on GitHub