iOS指南系列:如何解决奔溃问题-关于内存访问续2

Messing with Memory:

你知道演练过程了:运行程序,点击按钮,等待崩溃。没错!

iOS指南系列:如何解决奔溃问题-关于内存访问续2_第1张图片

又来一内存访问错误的问题 EXC_BAD_ACCESS, yikes! 幸运的是,Xcode中显示了你究竟在何处发生崩溃,在 buttonTapped: 方法:
	NSLog("You tapped on: %s", sender);

有时,这些错误可能需要在你的头脑里片刻或再度思考下,但同样,Xcode给了援助之手 - 只需轻按黄色三角形,看到什么是错的提示:

iOS指南系列:如何解决奔溃问题-关于内存访问续2_第2张图片

NSLog() 采用 Objective-C-type string, 不是过去的 old C-string, 需要插入 @ w :

	NSLog(@"You tapped on: %s", sender);

你会发现,黄色三角形警告没消失。这是因为此行的另一个错误,可能会或可能不会导致您的应用程序崩溃,这些都是有趣的。有时代码工作得很好- 在least appears工作得很好 - 在其他时间它会崩溃。 当然,这些各种各样的崩溃只发生在客户的设备,从未自己。)
让我们来看看新的警告是什么:

iOS指南系列:如何解决奔溃问题-关于内存访问续2_第3张图片

这个 %s 指定是用于变量类型 C-style strings. C-string 通常就是代表一段内存的字符内容,字符以数组方式存在,需要一个终止符号,通常是 “NUL character,” 通常代表了 0. 举个例子来说 C-string “Crash!” 在内存中的布局类似:

iOS指南系列:如何解决奔溃问题-关于内存访问续2_第4张图片

Whenever you use a function or method that expects a C-style string, you have to make sure the string ends with the value 0, or the function will not recognize that the string has ended.

Now, when you specify %s in an NSLog() format string – or in NSString’s stringWithFormat – then the parameter is interpreted as if it were a C-string. In this case, “sender” is the parameter, and it’s a pointer to a UIButton object, which is definitely not a C-string. If whatever “sender” points to contains a 0 byte, then the NSLog() will not crash, but output something such as:

每当你使用一个函数或方法,预计会用到C风格的字符串,你必须确定使0值作为字符串结束,否则程序不会承认已经结束的字符串的位置,一直读下去。
现在,当您指定在NSLog()格式字符串%S - NSString的stringWithFormat - ,那么该参数被解释为 它是一个C字符串。在这种情况下,“sender是参数,它是一个UIButton对象,这绝对不是一个C字符串的指针。幸运的话,如果任何“sender”对象内存布局中包含一个0/nil字节,然后NSLog()将不会崩溃,但输出的东西会是你完全无法想象到的,如:

You tapped on: xËj

实际上,你可以看到这个来自什么地方。再次运行程序,点击按钮,等待崩溃。现在,在左半边的调试窗格中,右键单击“sender*发件人查看内存选项(一定要选择一个与sender前面的星号)。

iOS指南系列:如何解决奔溃问题-关于内存访问续2_第5张图片

Xcode 会告诉你在内存中的具体内容,我们看到在某个位置有00,之前的内容就是  NSLog() 所输出的


iOS指南系列:如何解决奔溃问题-关于内存访问续2_第6张图片

然而,不能保证一定有一个NUL字节,你可以很容易地运行到EXC_BAD_ACCESS错误。如果你总是测试你的应用程序在模拟器上,可能不会发生很长一段时间,一般情况下,可能是在您的特定的测试环境中运行总是在你的青睐。这使得这些类型的错误非常难以追查。
当然,在这种情况下的Xcode已经警告你在错误的格式规范,所以这个特定的错误是很容易找到。但每当你使用C字符串或直接操纵内存,你必须非常小心,不要破坏周围的内存区块。
如果你够幸运的应用程序将始终崩溃和错误很容易找到,但更常见的,应用程序有时只会崩溃 - 使问题难以重现! - 然后追捕的错误,可以采取难遇。

很容易fix这个问题,采用%@,当然最后还是要明确适用类型,例如@f 给float。%i给int

	NSLog(@"You tapped on: %@", sender);

运行程序后,发现还是会出错哦,下回再分析:

2012-04-14 21:13:34.395 Problems[1297:f803] You tapped on: <UIRoundedRectButton: 0x6866200; frame = (119 189; 82 37); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x68662d0>>


译者总结:

1.还是不要忽视任何告警

2.基本的调试是通用的(windows/mac),看内存, 看布局,看特殊的字符?有没有pageheap/stack overfollow之类的检查?

你可能感兴趣的:(iOS指南系列:如何解决奔溃问题-关于内存访问续2)