转载一篇文章,debug的精神非常受用

文章出自:http://gracelancy.com/blog/2012/11/27/debug-objc-code/

作者简介:蓝晨钰(Lancy)目前在猿题库(yuantiku.com)任 iOS 研发工程师。

从一段奇葩的objc代码看代码规范的重要性

背景介绍

昨天,在和我一个朋友讨论,到底是用self.propertyName还是_propertyName来访问property,我认为应该使用self.propertyName,因为我在听Stanford Open Course的时候,苹果的工程师告诫要使用self.propertyName,不要使用_propertyName。而朋友认为应该使用_propertyName,因为google objc code style认为最好不要用self.propertyName。

我没看过google objc code style,我只看过objective c programming guide。在我的理解里property的作用在于根据参数生成相应的getter和setter。self.propertyName本质上既是调用getter函数的,而_propertyName直接访问成员函数,因为相应参数生成的getter和setter是不会被调用的。

再说,我还是决定相信apple,而不是google,毕竟Objc还是apple在支持和维护。

上代码


问题

这段代码是无效的,按下按钮之后,setupData被调用了,已经log确定dataArray已经改变,tableview的delegate和datasource都设置正确,确定numberOfRowsInSection被调用,奇葩的是cellForRowAtIndexPath没有调用,故而tableview没有改变。

奇葩的来了

朋友跟我说,你只要把[self.tableview reloadData]改成[_tableview reloadData],他就生效了。是的,他就生效了。你设一个断点在这个地方,然后把self.tableview和_tableviewpo出来,发现他们的指针是一样的。朋友说写这个代码的那货折腾了一天,百思不得其解,最后得出结论self.propertyName就是坑爹。

生效的修改方法

朋友提供的:

前面说的讲把[self.tableview reloadData]改成[_tableview reloadData]

把tableview的getter函数的init里面的self.view.bounds改成CGReckMake(0,0, 320, 480)

朋友试图用这个两个方法来说明,self.property是坑爹的。

我在初步debug的时候,由于我是property的拥护者,property自动生成setter和getter函数,我是不支持重写getter函数的,所以我将getter函数删掉,把初始化代码移到viewdidload里面。然后代码就生效了。

但是即使代码生效了,还是没有找到问题的关键,仍然没办法解释为什么[self.tableview reloadData]改成[_tableview reloadData]就能运行了,因为po出来的指针是完全一样的,这不科学。

真正的问题所在

在各种Stackoverflow,google无果之后,我还是着手准备深入debug。

通过各种断点和gdb,最后打印函数调用栈才让我发现了真正的问题所在。

整个程序的执行顺序是这样的:

initWithNibName(执行到[self setupData],没执行完) –>

第一次setupData(执行到[self.tableView reloadData],没执行完) –>

第一次执行tableview getter(到init,调用self.view,没执行完)->

viewDidLoad(到addSubview:self.tableView, 没执行完) –>

第二次执行tableview getter(问题在这里!第一次执行的时候没有init玩,所以又会执行一次!)->

回到4.viewDidLoad,这是add的subview是第二次的init而先init完的tableview –>

回到3.第一次执行getter,(又alloc了一次tableView,这是self.property指向的是第一次init而后init完成的tableview))

所以,显示在界面上的tableview根本不是self.tableview指向的tableview,故而根本没法刷新(cellForRowAtIndexPath,是当需要显示的时候才会调用的)。

那为什么把[self.tableview reloadData]改成[_tableview reloadData]就能生效了呢?因为这样在initWithNibName的第一次调用setupData,就不会在reload的时候调用tableview getter,也就不会有后面一连串的连锁反应。之后顺利在viewdidload的时候只调用一次,完成init。

知道了问题的关键,还能有各种各样让他生效的方法,就不吐槽了。

正确的写法

这段奇葩代码带给我最大的感触就是,不好好写规范的代码,各种问题都会坑死你。我认为规范的写法应该是

不要重写getter和setter函数,使用property生成的getter和setter

不要在vc的init的函数里面初始化,尤其是初始化视图。而应该在viewdidload里面初始化,保证self.view已经生成。(非ARC环境下还需要注意memory warning导致的viewdidload多次加载而多次初始化所带来的内存泄露问题。最安全的做法是lazy instantiation)

应该使用自顶向下的程序设计方法,保证程序的顺序执行和层次关系。不应该出现如上程序的跳来跳去的调用。

后记

帮人debug还是有好处的,让我结识了这位bug兄。也让我更加深入的了解了cocoa的变量访问机制,debug的时候顺带还测试了KVO。

Edit

我又重新去看了property和getter,setter的资料,也看了苹果对property的解释。最后我修正关于不要重写getter和setter函数的观点,更正为可以重写getter和setter,目的可以为lazy instantiation, UI updating, consistency checking,等。但需要注意如上程序的连锁反应。代码的灵活性和安全性

关于@property,经过和大家的讨论也有了一个结论:

Why property?

Most importantly, it provides safety and subclassablility for instance variables. Also provides “value” for lazy instantiation, UI updating, consistency checking, etc.

Lancy

11.27.2012

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

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,678评论 0 9
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,119评论 29 470
  • 前言:面试笔试都是必考语法知识点。请认真复习和深入研究OC。 目录:iOS-面试题-OC基础篇 (1) - (84...
    麦穗0615阅读 4,245评论 0 33
  • 早上被一电话叫醒-是社团的一个朋友,然后懒床15分钟 起床洗漱,然后和同学去食堂吃饭,去的时候已经快10点了,准备...
    小场面阅读 124评论 0 1
  • 文自/半糖门 我爸爱旧,什么都攒着,零七杂八一点舍不得,至今为止,我初中骑的自行车还留着,挂在一面墙上,破的那叫一...
    君半糖阅读 145评论 0 1