关于Aspects

https://github.com/steipete/Aspects

aspects是针对面向切面编程:Aspect Oriented Programming(AOP)的一种实现方案。AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。
以埋点为例,虽然现在已经有像友盟这样强大的第三方埋点方案,但是这并不能满足一些公司的业务需求,如果要完全自定义地进行埋点,监听并统计用户的行为,使用传统的方案,必然导致对整个项目的代码进行大范围的修改。而使用面向切面编程的思想,则可以将埋点和系统原有的逻辑解耦,悄悄地完成埋点。


下面来看看Aspects是如何帮助我们实现这点的。

还是举个例子来说明:
假设我们要统计某些页面的显示的次数,以往使用友盟来统计页面访问我们会这么做

1
2
3
4
5
6
7
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//do something
if(self.title){
[MobClick beginLogPageView:self.title];
}
}

聪明一点的做法当然是可以把它写在基类。这样至少不会影响太多的代码。但是如果是其他一些更加个性化的埋点,比如说点击某个按钮,通过不同的方法进入某个页面,注册所消耗的时间统计等等等等。。。。

有了Aspect 我们可以这么做

1
2
3
4
5
6
[UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
UIViewController* viewController = aspectInfo.instance;
if (viewController.title) {
[MobClick beginLogPageView:viewController.title];
}
} error:NULL];

当然,这块代码完全可以和原有的逻辑隔离。
先解释一下,Aspects针对NSObject实现了aspect_hookSelector的方法,顾名思义,使用一个钩hook住了UIViewController的viewWillAppear方法,withOptions可以有两个参数,一个是AspectPositionAfter,另一个是AspectPositionBefore,分别代表在原有方法执行前或者原有方法执行后执行该block,根本上相当于利用oc的runtime特性替换了原有的方法。
通过aspectInfo中的instance和arguments属性可以分别获得方法的方法体和参数,基本上也就是获得了整个方法执行的上下文。
特别需要注意的是,同一个继承树上的同一个方法只能被hook一次

阅读全文 »

Bug的发现

一次偶然的机会,发现了QQ的一个Bug。
复现过程如下:

  • 在QQ中通过任意途径打开一个pdf或者word文档
  • 单击全屏显示
  • 滑动返回到一半终止返回(再次回到浏览界面)
  • 再次滑动返回,就会观察到这样的场景————导航栏消失不见或者导航栏错位

当然,这是一个必现的Bug,而且我也相信类似的操作在很多别的应用中也会引发这个Bug,归根结底,这是iOS在引入了滑动返回后导航栏本身的一个Bug

阅读全文 »

事情的经过是这样的,项目的主页是一个由一个xib定义的scrollView,设置的contentSize是屏幕宽度的1.75倍,一共分三屏。

这样的布局设计在很多应用中应该是很常见的,并且从业务需求的角度往往需要在scrollView的delegate中根据scrollView的滑动状态和contentOffset做一些切换和调整。那么问题就来了!!!

源代码是这样的

1
2
3
4
5
6
7
8
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if(_scrollView.contentOffset.x > 0){
//do something
if (_scrollView.contentOffset.x > kScreenWidth) {
//代表scrollView进入了第三屏,需要做某些事情
}
}
}

但是这块业务在之后的测试中出现了一个很难复现的Bug。
那就是当滑动到中间屏幕(即contentOffset.x = kScreenWidth的时候),居然进入了>kScreenWidth的判断。
然后进入调试模式,居然发现此时的contentOffset = 321…..
321…..
坑爹么!这是!
于是就这么偶然地发现了这个惊天大坑!
在经过一系列的滑动之后,scrollView会出现contentOffset计算不准确的计算,这也就意味着在做一些针对contentOffset的判断的时候,用==的操作很容易出现问题。

那么解决方案就来了
把if里面的判断改成

1
fabs(_scrollView.contentOffset.x - 1.75 * kScreenWidth) <= 2.0

通过绝对值的模糊判断,解决了原先contentOffset计算不精确所导致的问题。

这也提醒了我,在程序中一些设计浮点数判断相等的时候,需要考虑到计算误差的情况。

当然,不管是此处的bug是因为通过autolayout来控制scrollView的contentOffset也好,还是本身scrollView的一个bug也好,反正这次踩过了坑,以后也就不会再踩了。

最近在给公司的项目做国际化,不得不说是一件很繁重的工作,因为公司项目使用的xib较多,所以既要考虑代码的国际化也要考虑xib的国际化,同时项目中还要求对权限请求提醒做国际化,种种种种。

网上相关国际化的博文有很多,不过并没有一个全面的针对代码、xib、storyboard以及项目配置整体的一个国际化的介绍,所以这里一口气就全部搬上来了。

代码的国际化

给项目添加国际化

给项目添加国际化

阅读全文 »

这周公司酝酿了三个多月的项目要提交,开发组里忙的天昏地暗。最后一天居然忙里偷闲把Blog给挂了上去,虽然这个博客也已经是酝酿了有两个月了,之前很多次都因为各种各样的问题而搁置了。于是我也要开始玩博客了~

感觉大学水了两年,没有很深入地去钻研一门技术,杂七杂八的东西接触了不少,到大二下学期才真正开始专心弄iOS,跟着创业团队做了几个项目,然后现在在一家创业公司做实习生,虽然挂着实习生的名,但是干着正式员工的活。公司里有很Nice的队友,虽然工作很忙,但确实我是学到了很多以前从来没有接触过的东西。

暂时给小站起名叫做“XXX的学习笔记”吧,类似这样的名字其实很多,最近一段时间新学到很多有意思的东西,踩了不少坑,正好可以跟大家拿出来分享一下。

嗯,暂时就这样了