[译]如何提高 iOS 开发水平

Clash of the Coders 这样的比赛,很有意思。在72小时不休不眠的时间内显示精神力量,在Objective-C运行时,UIAplication,堆栈层进行暴力行为。这是个创举,为了颠覆它而使用我所有平台的知识。

那天我和我一个 Ranch 同事聊天,他说,“Hey MarkD,怎样让我学习到所有这些细节?我觉得我好像困在地狱的土地上,只会使用 tableviews 和诸如此类的东西。“ 说一个艰巨的问题,特别是来自一个有大量技能的工程师。“嗯,你刚才做的东西?”,不是一个好的答案。

我在编程行业(实际上是靠它谋生)23年了。这比我的一些同事活的时间还长。这是一个很可怕的事情,滚开。多年来,我已经养成一种学习和探索的习惯,这是一种很不错的事情。当然,每个人是不一样,但以下是我如何回答他的问题。

阅读

大量阅读。在你的大脑中填充信息。有很多的书籍和博客,特别是相比于所有 Mac 编程书只能装在一个宜家书架上的一层的时代。那时我最喜欢的书是 Rob Napier 和 Mugunth Kumar 的 iOS 6: Pushing The Limits。我必须也提下Advanced Mac OS X Programming : The Big Nerd Ranch Guide,因为它挖掘了 厚实的 OS X internals(这本书的电子本足以让你的 Kindle 变重)。有一些已经过时了,但一个实实在在的操作系统在意的各种细节是让人着迷的。

我们生活在一个信息丰富的网络时代。除了这个不起眼的博客,你也应当阅读 Mike Ash 的 NSBlog。我也经常阅读 NShipster Jeremy W. Sherman 博客。

别忘了要阅读官方文档。浏览 Xcode 中的 Cocoa / UIKit 文档。我在我的 iPad 上装了 DocSets,这样在我等待的时间里我可以略读这些文档。别把自己限制在你一直使用的类上。把你的时间都花在 NSTableView?读下 IOService 吧。你可能永远不会使用它,但你可能会发现一些能够激发进一步学习的主题。

我尝试定期通读编译器和调试器文档。gdb 有很好的文档。gdb 至今仍然相关-lldb 在设备上运行仍然有些不可靠。lldb 网站上有一些支持文档,所以坚持它的内置帮助来学习所有有用的命令。确保阅读所有的东西。如果你看到一个深奥难懂的特征,尝试揣摩它为什么存在。

编译器内幕可以在 http://clang.llvm.org 网站找到。也别忘了头文件,它们包含很多有用的信息。

我记不住所有东西。现在我记不住大部分东西。但我有印象“我觉得我之前读了这类东西。它在哪里?” 深思下就提醒了我 “是的,Jeremy 在他的博客上用12行代码重新实现了 Cocoa,他有一个很酷的 higher-order-messaging 分类,可能会有用。

剖析

要学习东西是如何工作的,我喜欢研究东西是如何工作的。知道谁调用谁是个关键。“谁创建了这个 undo 管理器?” 这是解决 bug 的关键。当 MPMusicPlayerController 在播放列表中一首一首播放的时候,检查应用程序中到处飞的通知可以帮你发现它在做什么。

我们有很多强大的工具来窥视我们的程序和库。你很可能不会每天都使用它们中的一个。有些你可能一个月或一季度才使用一次。但在你们的工具包中有他们是好事。

源码

clang 和 lldb 的源码很容易得到,你可以下载它们并编译。想知道这个语言中某个东西如何工作?在源码中找找看是否能发现它。你也可以在 http://www.opensource.apple.com 上得到 Core Foundation 源码中的一个适当的子集(其中包含了很多其他东西)。真正有趣的部分是“xnu”-内核,“CF”-Core Foundation,还有 objc-object-C 运行时。当然,钻研 Cocoa 头文件,发现一些你可能不理解的,比如 NSAssert。然后找出它是如何工作的。

调试器:你可以在任何可见的变量符号上设置断点,不管是你自己的代码,还是二进制库中的方法和函数。你可以在 Xcode 中通过添加一个符号断点直接进入断点。下面是我在 UIApplication 中的 _performMemoryWarning: 私有方法中添加了一个断点。

你可以在模拟器中触发一个内存警告,看看它是否被处理了:

通知 spying:通知是常用的去耦代码。一些有趣的事情发生,然后通知被发送了。NSNotificationCenter 和 朋友是如此便利以致几乎所有的东西都使用它。你可以添加一个通知探测来打印所有漂浮的通知。

DTrace:我知道人们希望我停止谈论 DTrace。我如何发现 _performMemoryWarning 符号?它显然不在任何苹果的文档中,下划线开头表明这是“私有 API”,这是别插手的标志。我在模拟器中 DTraced 一个问题,触发了一个内存警告,然后看到了所发生的。程序崩溃时我想再解答其他一些问题,比如“UITouch 在哪里被创建并分发?”,还有 “当我加载一个 nib 文件时出发了文件系统的什么?”。这样诞生了一个小的工具脚本:spy.d(点击这里)。

spy.d 是一个简单的脚本,可追踪 objc 提供的 Object-C 消息,忽略常用消息列表上的消息,然后为“特别有趣”的消息列表上的方法显示完整的栈追踪信息。我运行 spy.d 然后在模拟器上触发了一个内存警告。

# ./spy.d  61271
...
UIApplication -didReceiveMemoryWarning
NSNotificationCenter +defaultCenter
NSNotificationCenter -postNotificationName:object:
...
UIImage(UIImageInternal) +_flushCache:
UIViewController +_traverseViewControllerHierarchyWithDelayedRelease:
UIViewController -didReceiveMemoryWarning
UIViewController -_traverseViewControllerHierarchyFromLevel:withBlock:
RMScheduleVC -didReceiveMemoryWarning

UIApplication得到一个内存警告。它发送一个通知。UIImage 刷新它的缓存作为响应。然后 UIViewController 的类方法遍历控制器的继承并告诉每个类它得到一个内存警告,然后它冒泡到我代码中的 RMScheduleVC。

class-dump: Objective-C 运行时元数据相当丰富。你可以在运行时浏览类和他们的代码然后发现所有可以玩的很酷的玩具。这个信息实际上存储在应用程序二进制中(还有对象文件和库),然后可以被抽取。Steve Nygard 的 class-dump 会提取这个元数据并将他找到的所有类生成 @interfaces。例如,从 UIApplication 中:

...
- (void)_purgeSharedInstances;
- (void)setReceivesMemoryWarnings:(BOOL)arg1;
- (void)_receivedMemoryNotification;
- (void)didReceiveMemoryWarning;
- (void)_performMemoryWarning;
- (BOOL)_isHandlingMemoryWarning;
- (void)_processScriptEvent:(struct __GSEvent *)arg1;
- (void)_dumpScreenContents:(struct __GSEvent *)arg1;
- (void)_dumpUIHierarchy:(struct __GSEvent *)arg1;
- (void)setSystemVolumeHUDEnabled:(BOOL)arg1;
...

这里是所有进行中的有趣的事情。这里你可以放断点,并在调用堆栈中浏览。你也可以潜入到实现中。

Hopper Disassmbler:Hopper Disassembler 是个阅读对象代码并显示相应的汇编语言的工具。这里它正在查看 UIKit,UIApplication 的 _performMemoryWarning 实现方法。

Hopper 简洁之处在于,它能将汇编语言转换成伪代码,这样你可以更好的理出代码流程。

这也是通过例子学习汇编语言的一种灵巧方式。需要注意的是你在查看的是编译器产生的代码,所以当优化时它并没有太大意义。

Instruments:Instruments 不仅仅用于发现性能问题。它可以用于寻找所有有问题代码中的位置,包括你自己写的代码还有库中的代码,你可以在其他工具开始进行攻击。想知道 UISlider 如何做现场追踪?在一个有 slider 的应用程序中用 Instrument,移动10秒,然后看看调用堆栈的顶部是什么。然后你可以开始在模拟器中应用 DTrace,或者 disassembling,然后看发生了什么。

一个简短警告:-小心应用你从这些工具中获取的信息。他们对于调试和发现事情如何工作是非常棒的。依赖这些工具中的实现细则和私有 API 可能导致一个脆弱的软件,会破坏主要或次要的 OS 版本。如果你正在编写的软件是针对付费用户,或者针对要用这个软件做重要事情的用户。你是一个专业的程序员。确保要像一个专业的程序员。

实验

现在你有一个工具舰队,是时候学习一些东西。通过动手操作学习最好。弄脏和犯错误!有兴趣深入学习 UITableView?写大量 table view 代码。浏览文档。查看你之前可能没用过的 API 头文件,并使用这些看看会发生什么。阅读一些博客,使用 Class-dump,寻找一些令人好奇的私有 API,然后看你是否能在常规接口中触发它。使用 DTrace 查看消息流。添加通知监测看看它试图告诉你什么工具包。如果事情不能正常工作,使用你常用的调试技巧,然后找出为什么不能工作。看看你是否能自己重新实现它。

我倾向于在 UIKit / AppKit 下浏览代码,因此我写了很多联系数据结构和语言特征的小程序。Steve Sparks,我在 Clash Crime 中的拍档,有它的游乐场,一个有 tab view 和 导航控制器的 Xcode 项目,他可以在任何时候在这个项目中做实验。想玩玩 UIScrollView 暴力?折腾一个新的视图控制器,启动它,现在你可以在模拟器或设备中玩它。保持代码版本控制,然后你可以有一个你所有实验的记录。

消化

你决定开始学习一些知识。你写了大量代码。你调试了。可能你也做了大量笔记。现在是时候消化所有这些了。带着它进入梦乡。来个骑行。去洗个长时间的澡澡。让所有你接触的新知识形成模式。看看你是否能从这些模式中建立一些抽象概念,然后在其他类中应用它。现今的许多软件开发都可以机械化,它们有一些特征需要被实现,你整合在一起的常用类集合。

同化步骤最有趣的是,在你的大脑中开始建立关系。例子中的很多都来自于我们在 Clash 入口中出现的一个简单的问题:“我们想在应用程序命令行触发内存警告”,来帮助调试内存并缓存问题。调查过程如下:

  • 我们可以在模拟器中触发内存警告
  • 使用通知监测看看是否有通知被发送。为什么有。我们可以 hook 进去并对它们作出响应
  • 发送不会实际触发东西的通知。没用。我想知道为什么。
  • 是否有我寻找的其他内存警告方法?使用 class-dump,看看在哪里
  • 发送 _performMemoryWarning 给当前陷入内存警告机制的应用程序实例。为什么它没有发送通知?
  • 只为了有趣,使用 Hopper,看看实际发生了什么。噢,看,它有视图控制器继承和 sqlite,在发送内存警告通知时它们没有被激发。
  • 添加一个内存警告 button 来调试 console,嵌套在 #if 块中来防止它被释放到外面。

总结

这里有很多我学习 nerdskills 的秘密策略:

  • 阅读-往大脑中塞很多事实。有些事实会一直在,我发现那个东西很有趣,所以这是个愉快的消遣。
  • 剖析-舒适地使用大范围的工具,从高级到低级水平,别害怕使用它们。别害怕怪异地使用它们。DTrace 会是个大铁锤。但有时它能在小地方用并粉粹一个 bug。使用这些工具来研究软件如何工作。保证你会使用这些知识做好事,而不是坏事。
  • 实验-写代码。写大量代码。实验。玩所有发现的新玩具。梳理出模式。
  • 吸收-反省。激动,冲洗,重复。并在接下来的20年继续从事它。建立深度的技能是一个长期的工作。

本文翻译自 Mark Dalrymple 的博文 LevelingUp

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容