问题现象
最近一个项目,需要使用NSTableView显示一个列表,列表上显示用户头像和用户信息。在用户很少的时候,也就是item很少的时候,没啥问题,但是找了朋友的帐号来测试的时候,他的账号下有八百多个用户,这就让这个程序出现诡异问题了。在快速滚动的时候,出现了一个现象,当滚动停止时,列表上的头像不断的在变化,一直到变化到一段时间后,才会停止。
初步分析这个问题很奇怪,不过从问题的表象上来看,似乎是图片刷新的问题,Cell的文字部分似乎是不存在这个问题的。当然经过google了一段时间后发现,大家都是搞的UITableView的-,-UI**的。。。iOS这么火,Mac开发快成没人爱的孩子了。。。好吧,那还是自己继续研究了。
问题分析
分析问题,个人比较喜欢的就是观察现象,之后进行思考和分析,那么再次回到表象后,仔细观察后发现图片的刷新那都是有规律的,滑动的越多那么刷新的次数就越多,慢速滑动的时候却不会出现这样的情况。那么再次猜测是否是刷新很慢的问题?因为网络连接很慢,那么会不会是导致了图片在不断的刷新?但是总觉得每一个View应该是独立的,并且每次创建View的时候,我都把图片设为了nil,但是依然存在这个问题,这时候才想起来了NSTableView有一个View重用的机制,如果一个View走出了可视区,并且进入了reuse queue的话,那么他就会被重用,基于上面的观察和思考后,再次分析代码,终于发现了问题的症结所在。
1 | + (void)downloadImageWithURLString:(NSString *)urlString onComplate:(void (^)(NSImage *image))complate |
上面是获取图片的代码,这样,每次加载的时候都会先将myImage设置为nil,之后通过AFImageRequestOperation异步的获取。这么看似乎是没有问题的,因为每次使用之前我都设置为了nil,之后异步的从网络获取图片并加载。那么结合了NSTableView的View重用机制后,就会是下面这样的情况。
假设我有很多记录,并且每次都只显示其中的10个记录,并且我的网速不慢不快,那么从1快速滑动到600或者更多,那么在滑动过程中,某个View被重用了,并重新加载了很多次(方便点就认为是10次吧),那么会发生下面现象:
- 加载需要显示的东西(文字啊,名字啊,年龄啊之类的东西)
- 建立AFImageRequestOperation并启动获取图像的进程。
- 滑出显示区外,进入reuse queue。
- 再次进入显示区域,进入第一步。
就这样,每次重用时都发生了上面的过程,如果你的网速非常快(0秒加载),那上面的代码妥妥的。但是肯定很多童鞋跟我一样,在可怜的2M小水管下,并且每个图片都需要穿越这伟大的防火长城,那必须得卡,必须出错。
上面的过程中,AFImageRequestOperation完成后,就会马上执行complate的代码,马上刷新图片,那么如果已经滑倒600了,我才把图片下载完,那肯定是顺着下载完成的顺序,不断把myImage刷新10次,这样就看到了问题表象,图片象是放幻灯片一样的,不断切换了。
解决思路
问题原因找到了,那就好解决了,借用让子弹飞里面一句话,狠一点“杀人要诛心”啊,不但要把你的图片干掉(设成nil),还要让你断了那个想念(继续从网络加载图片),接下来我们看看怎么做的。
1 | @interface MyTableCellView : NSTableCellView |
总结
嗯嗯,总结下,刚好领导再开XXXXXX检查总结会,我也来总结下分析问题还是要从现象入手,结合平台的资料,再分析代码,才能找到问题的根源,并且也是因为自己对用的东西不是那么熟悉导致的。
也希望将来在Mac上耕耘的童鞋更多啦~~
最后欢迎大家订阅我的微信公众号 Little Code
- 公众号主要发一些开发相关的技术文章
- 谈谈自己对技术的理解,经验
- 也许会谈谈人生的感悟
- 本人不是很高产,但是力求保证质量和原创