移动开发笔记

看到的,学到的,与大家一起分享。

自己写的一个滑动后退类

很多 iOS 应用都有向后滑动后退的功能,这个功能挺实用的,所以我自己做了一个简单的封装,现在支持 UINavigationViewController 的层级滑动,大家可以到 GitHub 上面查看: MEBackTrack

调用方法:

1
2
3
4
5
6
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

        [[MEBackTrackManager sharedManager] registerNavigationController:(UINavigationController *)self.navigationController];

}

让Xcode的报错提示更加精准

我们在用 Xcode 进行开发的时候,经常会用它来调试程序的崩溃或者异常问题。而我们经常会收到类似这样的报错信息:

1
2
3
4
*** Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contains NaN: [nan 0]'
*** First throw call stack:
(0x39f972a3 0x328b697f 0x39f971c5 0x325da953 0x325da87b 0x325da80b 0x36e1caf5 0x36e34661 0x36e34351 0x52bbb 0x36e3a595 0x36e7ad79 0x36e76aed 0x36eb81d1 0x52943 0x36e7bad9 0x36e7b663 0x36e7384b 0x36e1bc41 0x36e1b6d5 0x36e1b123 0x35e185a3 0x35e181d3 0x39f6c173 0x39f6c117 0x39f6af99 0x39eddebd 0x39eddd49 0x36e72485 0x36e6f301 0x52589 0x52510)
libc++abi.dylib: terminate called throwing an exception

除法运算要小心

除法运算,是我们日常开发工作中常会用到的操作。这虽然是一个看似很简单的操作,但如果写代码的时候不加留意的话,也会让你很头疼。

大家应该还记得,在大学关于编程的课上面,老师基本上都会提到除 0 问题,会返回 NaN 值之类的。当有了一些开发经验之后,我们会对这个问题有更深入的理解。

这里给大家举一个很简单的例子,比如我们开发一个 iOS 应用,我们常常会计算各个 View 的大小尺寸,这里就会经常用到除法:

1
someView.frame = CGRectMake(100.0f,100.0f,200.0f,200.0f);

上面那一行代码,我相信所有做过 iOS 开发的同学们都会用到过。虽然是看起来这么简单的一个操作,但是如果不加注意的话,也会引发比较严重的问题。

比如我们常常会根据一些算数运算来动态的设置 View 的 frame, 再给大家看一个例子:

1
2
3
4
5
6
CGFloat division;

....
....

someView.frame = CGRectMake(100.0f,100.0f, division, division);

我们简单看一下,好像没发现有什么不对。但要注意的是,我们这次用 division 这个浮点型变量来创建这个 View 的 frame,但是我们不能确定 division 这个变量中存放的是什么东西。

虽然上述代码能够顺利的通过编译器检测,但如果这个变量中存的是一个 NaN 值,就会导致我们的应用崩溃。并且这种崩溃问题很难调试,而且也不容易百分之百的重现出来。

如果对这个不加留意的话,这种情况在我们的应用中发生的可能性还是很大的。比如我们有时候会用一个数值除以某个 View 的宽度来计算另一个 View 的宽度,但是如果恰巧第一个 View 的宽度是 0 的话,那么计算出来的就是一个 NaN 值。 ,并且如果没经过任何隐式类型转换的话,这个 NaN 值就会直接传递给第二个视图,那么应用就会立即崩溃。

本人就曾经应为这个问题被困惑了很久,所以在这里写出来,希望能够节省大家调试程序的时间,并对大家有所帮助。

使用 Apachetop 实时监测web服务器运行状况

对于 Linux 下使用 Apache 作为 Web 服务器来说,大家也许经常会需要查看服务器的实时运行情况,比如哪些 URL 的访问量最大,服务器每秒的请求数,等等。 apachetop 就是这样一个工具, 能够让你实时的监测 apache 服务器的运行状况。

apachetop 是一个命令行工具,它的运行原理是通过分析 apache 服务器的日志文件,来向用户展示服务器的运行情况。

使用Xcode进行单元测试 —— 环境配置

单元测试,是保证产品质量的一个好方法。 移动产品会经常的更新升级,每次版本更新的时候,都需要花费大量的精力来进行测试。 使用单元测试,则可以减少这类重复性的工作。 能够让测试变得更加自动化并且大幅提高测试的效率。 Xcode 为我们集成了单元测试框架,OCUnit。让我们来看看如何在 Xcode 配置单元测试:

  • 首先按照下面的图示,创建一个新的 target:

  • 在接下来的界面中,按照下图选择,然后点击 Next:

  • 填写相应的名称,然后点击 Finish。

  • 这时候,Xcode 中会新增加一个分组,以你刚才输入的名称命名。

在这里面已经帮我们创建好一个单元测试了,上图中的 test.h 和 test.m 就是 Xcode 为我们创建的测试。

  • 现在我们切换一下 Scheme, 切换到我们新创建的单元测试上,逻辑测试只能在模拟器上面运行,所以运行目标要选择模拟器:

现在,按下 Cmd+U 就可以运行单元测试了。

  • 测试运行完成后,你应该会看到这个情况:

测试失败了,失败的原因很容易发现,我们在 testExample 调用了 STFail 这个宏,从它的名字就可以看出来,一旦调用这个宏,测试就会失败。 所以,我们把这个行代码删除掉,这时候 test.m 这个文件的内容应该是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#import "test.h"

@implementation test

- (void)setUp
{
    [super setUp];

    // Set-up code here.
}

- (void)tearDown
{
    // Tear-down code here.

    [super tearDown];
}

- (void)testExample
{

}

@end
  • 修改完代码后,再按下 Cmd+U 重新运行测试,这时候你应该在控制台中看到类似这样的输出:
1
2
3
4
5
6
7
8
9
2013-01-15 22:22:34.234 otest[7914:303] Unknown Device Type. Using UIUserInterfaceIdiomPad based on screen size
Test Suite '/Users/mengxiangping/Library/Developer/Xcode/DerivedData/Test-aexhdmmbnjmqrzbolfjyptdprrif/Build/Products/Debug-iphonesimulator/test.octest(Tests)' started at 2013-01-15 14:22:34 +0000
Test Suite 'test' started at 2013-01-15 14:22:34 +0000
Test Case '-[test testExample]' started.
Test Case '-[test testExample]' passed (0.000 seconds).
Test Suite 'test' finished at 2013-01-15 14:22:34 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite '/Users/spring/Library/Developer/Xcode/DerivedData/Test-aexhdmmbnjmqrzbolfjyptdprrif/Build/Products/Debug-iphonesimulator/test.octest(Tests)' finished at 2013-01-15 14:22:34 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.001) seconds

最后一行的内容表示测试成功了。到此为止,你的单元测试环境就搭建成功了。接下来就可以写你自己的测试了。

CFBundleAllowMixedLocalizations 开启系统预定义的本地化功能

在 iOS 应用程序中,很多控件都集成了本地化功能,比如,在 UIWebView 中的网页里面选择一个文本框,然后键盘上面会出现,前一项,后一项按钮。 这些按钮就会被系统根据当前设备的语言环境,进行本地化。 但这些控件是否对特定的语言环境进行本地化,还取决于你应用的配置。 iOS 默认只对你应用支持的语言进行本地化。 比如,每个应用的 Info.plist 中都有一个 CFBundleDevelopmentRegion 键, 而在默认情况下,它的值是 en。 换句话说就是你的应用仅支持英文环境。 这时,不管你应用所处的设备是怎样的语言环境,那么系统都只会按照英文进行本地化。还是以刚才 UIWebView 的例子来说,这时键盘上面会显示 “Previous”, “Next” 这些英文按钮。

在中文语言环境下 UIWebView 仍然显示英文按钮:

如果你需要系统帮你进行更多的本地化,那么有两种方法。 一种就是指明你应用支持的语言, 可以通过建立 *.lproj 来添加新的语言支持。 但是如果你想对所有的语言都进行本地化,那么这种方法就很麻烦了。 所以 iOS 提供了另外一种方式, CFBundleAllowMixedLocalizations。 我们只需要在项目的 Info.plist 文件中将这个键的值设置为 true。 顾名思义,这个键允许混合形式的本地化。 也就是说,当你设置了这个键之后,不管你的应用是否支持当前设备的语言环境,iOS 系统都会尽可能都根据当前的语言进行本地化。

可以通过在 Info.plist 编辑器中添加这个选项来设置:

应用了这个键之后,在中文语言环境下 UIWebView 的效果如下: