最基本的调试是NSLog及DEBUG预处理器宏

2018-09-07 15:10:08 浏览数 (1)

最基本的调试是NSLog及DEBUG预处理器宏

在系统控制台显示日志信息运行应用程序时是最早调试机制之一,利用log你可以查看应用程序的运行记录,当程序运行完毕,你可以长时间查看。此外,您的应用程序运行期间,可以观察所产生并写入到控制台,在您的应用程序它们所描述正在发生的事件的日志消息。作为一个开发者你是用NSLog的在console中显示的文本和信息的完全控制权,log可以发现即使是最难查找一个应用程序的问题.

此文档关于有关NSLog的功能及DEBUG预处理程序宏实际考虑为调试有用的对话

下面是NSLog调用的一个例子。

代码语言:javascript复制
NSString *message = @"test message";
NSLog( @"Here is a test message: '%@'", message );

并且,对于上述说法,控制台输出将显示如下:

代码语言:javascript复制
Here is a test message: 'test message'

这真的就是这么简单!而且,在这个文件中的这个时刻,你现在有足够的信息来开始使用NSLog的调试您的应用程序.但是,你应该继续往下看:在本文档的剩余部分补充说,你可以使用授权您可以在您的项目更有效地使用记录更多详细信息。

此文档适用于所有iOS和OS X开发,本示例假定正在使用Xcode的读者,是熟悉的Objective-C语言,并了解使用C语言预处理程序的基础知识。

[TOC]

在哪里可以找到NSLog的输出

有史以来Founction框架的NSLog功能一直适用于iOSOSX的个个版本。因此,您可以依赖它是可用于在任何苹果的平台,让您的应用程序将运行调试用的。NSLog的输出消息记录到苹果系统日志工具或控制台应用程序(通常以时间及进程ID作为前缀)。许多系统框架中使用NSLog的用于记录异常和错误,但不要求来限制及其使用于上述目的这也是完全可以接受的使用NSLog的输出变量值,参数,函数结果,堆栈跟踪等信息,所以你可以看到什么是在你的代码在运行时发生。

控制台输出可以出现在许多地方,包括(但不限于)Xcode和控制台应用程序,参考有关从您的应用程序的调用NSLog的找到控制台输出的更多信息,请参见技术Q&A QA1747:调试部署iOS应用

如何调用NSLog的

Founction框架NSLog功能的工作就像标准C库printf函数,最大的区别在于格式字符串被指定为“* NSString的”类型的值,而不是C风格的字符串

简单的例子

这里是展示如何调用NSLog的一个例子:

代码语言:javascript复制
NSString *outputData = @"A quick brown fox jumps over a lazy dog!";
 
NSLog( @"text: %@", outputData );
 
/* Comment:
 
    @"text: %@" - is the printf style formatting template for output (an NSString *)
 
    outputData - refers to to the text we wish to display (also an NSString *)
 
*/

而且,这里是输出的显示方式:

代码语言:javascript复制
text: A quick brown fox jumps over a lazy dog!
高级详细信息

出现用于NSLog的函数定义如下:

代码语言:javascript复制
void NSLog(NSString *format, ...);

注意第一个参数是一个格式化字符串,它可以含有意味着额外的参数之后期望特殊的替换标记.如果关心和关注不能采取措施,确保格式字符串的内容匹配起来,其余的参数,您的应用程序可能会崩溃(或者,至少是,它将输出不可用的数据到控制台)

像printf函数,使用NSLog的标记替换:

然而,出现在Objective-C%@,用于指示及其对应的参数应该是一个Objective-C的对象一个额外取代标记提供。

除了%@替换标识所有常规的printf风格替换标记是供您使用

关于有关NSLog的使用的替换标记的详细信息,请参见“字符串编程指南”的“字符串格式说明”部分。

好东西要在日志文件包括

日志记录允许您创建描述您的应用程序,你可以在你的闲暇之后分析操作的抄本。因此,你想在你的日志尽可能多的有用信息,这样更容易在你的应用程序运行期间让你真正看到正在发生的事情。

下面是一些通常包含在一些解释日志的一些项目:

逻辑和分支

新增您代码的逻辑内部的日志语句将帮助您了解正在被执行的部分,并正在使用你的逻辑,分支机构

日志对于十分复杂的程序落实十分有用的,你可以看到运行期间的程序逻辑。

独特且易于查找文本模式

在每个日志声明,它是有用的,包括一些独特的并且容易找到的文本模式,所以如果你确定该日志语句有问题,可以很容易地通过你的源文件搜索和找到它的位置

变量和属性值

你在你的应用程序关键地方打印变量和属性可以验证这些值是否是允许的范围之内。在日志打印错误信息,可以帮助你识别超出值范围的这一种情况。

除了用%@标记,任何在Printf使用的标记都可以在格式化字符串中使用。这将允许您显示许多不同类型的值,更多关于格式化信息你可以参考“字符串编程指南”的“字符串格式说明”部分

printf函数提供了大量用于打印数字替换标记(例如%d,%ld,%f)为方便起见,你可以使用Objective-C的Box能力,以节省时间,避免编译器警告。例如,以下内容:

代码语言:javascript复制
double myNumber = 7.7;
NSLog(@"number: %@", @(myNumber));

打印如下

代码语言:javascript复制
number: 7.7

这种技术适用于所有数字类型,编译器意识到(或签定任何大小的无符号整数或浮点数 - 8,16,32或64位),并且将任何必要的强制类型转换为你而不会产生的任何编译器警告

谁正在被调用

分析应用程序的操作是至关重要的,你可以知道那些程序那些功能被顺序调用。在这种情况下,它是添加接近的方法和函数定义之初即只需打印出函数名称的声明NSLog的一个很好的主意。

代码语言:javascript复制
- (void)pressButton:(id)sender
{
    NSLog( @"calling: %s", __PRETTY_FUNCTION__ );
    ....

这里,预定义的编译时间变量PRETTY_FUNCTION(一个C风格字符串)被用于打印函数的名称调用.当你分析大量的功能代码,你想知道正在调用你代理方法的层次是非常有用的。

以上将打印在console以下内容:

代码语言:javascript复制
calling: -[MyObjectClassName pressButton:]

PRETTY_FUNCTION编译time变量和其他类似在技术Q&A QA1669讨论:改进了日志记录在Objective-C。

记录你的堆栈信息

当检查崩溃日志,在堆栈中是非常宝贵找出导致的任何特定情况下的连锁事件。当使用NSLog进行调试,您可以通过调用NSThread-callStackSymbols类方法随时检索当前堆栈跟踪的副本。你可以在堆栈中使用%@打印NSArray的堆栈的信息。

代码语言:javascript复制
NSLog(@"%@", [NSThread callStackSymbols]);

上面的语句输出是下面的样子。

代码语言:javascript复制
2014-04-30 18:44:30.075 AVCustomEdit[52779:60b] (
 0  AVCustomEdit      0x0000efa6 -[APLSimpleEditor buildCompositionObjectsForPlayback:]   278
 1  AVCustomEdit      0x0000686e -[APLViewController viewDidAppear:]   590
 2  UIKit             0x007a4099 -[UIViewController _setViewAppearState:isAnimating:]   526
 3  UIKit             0x007a4617 -[UIViewController __viewDidAppear:]   146
 4  UIKit             0x007a49aa -[UIViewController _executeAfterAppearanceBlock]   63
 5  UIKit             0x0069f0d0 ___afterCACommitHandler_block_invoke_2   33
 6  UIKit             0x0069f055 _applyBlockToCFArrayCopiedToStack   403
 7  UIKit             0x0069ee9a _afterCACommitHandler   568
 8  CoreFoundation    0x029db2bf __CFRunLoopDoObservers   399
 9  CoreFoundation    0x029b9254 __CFRunLoopRun   1076
 10 CoreFoundation    0x029b89d3 CFRunLoopRunSpecific   467
 11 CoreFoundation    0x029b87eb CFRunLoopRunInMode   123
 12 GraphicsServices  0x0318b5ee GSEventRunModal   192
 13 GraphicsServices  0x0318b42b GSEventRun   104
 14 UIKit             0x00681f9b UIApplicationMain   1225
 15 AVCustomEdit      0x000026bd main   141
 16 libdyld.dylib     0x0269e701 start   1
)

该DEBUG预处理程序宏

简而言之,该DEBUG处理器宏作用一样,你可以打开和关闭一部分的调试代码。具体地,Debug宏旨在被用于打开和关闭相关的调试中不同部分源代码.在Xcode的默认配置中,调试默认为1,发布为0.而且,你可以利用它来自动地包含额外的调试和记录代码的调试版本。

下面是Debug使用的一个例子。

代码语言:javascript复制
- (void)pressButton:(id)sender
{
#if DEBUG
    NSLog(@"preparing to press button!");
#endif
    [self prepareForButtonPress];
 
#if DEBUG
    NSLog(@"pressing button!");
#endif
 
    [self activatePressButtonSequence:self withCompletion:^{
#if DEBUG
        NSLog(@"button sequence complete.");
#endif
            [self buttonPowerDown];
        }];
    NSLog(@"This line has no DEBUG macro, so it gets printed in both debug and release builds!");
}

调试版本(DEBUG == 1)将输出下面的信息

代码语言:javascript复制
preparing to press button!
pressing button!
button sequence complete.
This line has no DEBUG macro, so it gets printed in both debug and release builds!

发布版本(DEBUG == 0)将输出下面的信息

代码语言:javascript复制
This line has no DEBUG macro, so it gets printed in both debug and release builds!

NSLog需要时间去执行,如果你在你的应用程序里面加了很多这样的代码,将加大你程序的运行时间。在测试过程中,这通常不是问题。但是在发布的时候最好删除所有的打印,让用户体验最好的性能,不是打印一大堆看不懂的信息。正因为如此,开发者可以使用Debug宏可以让NSLog只有在调试的时候出现。

在Xcode里面的DEBUG

在Xcode中DEBUG定义调试模式,预编译宏可以编译DEBUG可以让你DEBUG模式运行程序。如果你不确定你是否定义了,可以通过打开你工程Build Setting搜索预处理,确保在Debug模式DEBUG ==1。如果还没有定义,你可以手动的添加,预编译宏是区分大小写的。

​ 图一在Xcode设置DEBUG预编译宏

Paste_Image.png

添加更多的LOG

如果你已经添加了log你还是找不到问题的所在,你可以添加很多的Log去查找。继续添加记录到您的应用程序,直到你能够获取足够的信息,以便您能够明白发生了什么。

NSLog是调试的朋友

每一个iOS或者OSX的开发人员无时无刻的使用NSLog调试你的程序,而且,你知道开发者可能对如何使用它的一些有趣的想法可能对你有帮助。如果您对NSLog的任何其他问题或需要帮助调试,请询问您的问题在适当的Mac或iOS开发者论坛调试的部分。

如果您对本文有任何意见,请通过反馈标签提交的文档的底部

更多的资源

  • 调试部署iOS应用
  • 在Objective-C改进了日志记录
  • Mac OS X的调试魔术
  • “字符串编程指南”的“字符串格式说明”
  • 如何使用调试时断言
  • iOS的调试魔术

0 人点赞