NS在iPhone中使用Objective-C记录方法名称


153

当前,我们正在为自己定义一个扩展的日志机制,以打印出日志的类名和源行号。

#define NCLog(s, ...) NSLog(@"<%@:%d> %@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], \
    __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__])

例如,当我调用NCLog(@“ Hello world”);时,输出将是:

<ApplicationDelegate:10>Hello world

现在,我还想注销方法名称,例如:

<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world

因此,当我们知道要调用哪个方法时,这将使调试变得更容易。我知道我们也有Xcode调试器,但是有时我也想通过注销来进行调试。


在上一个iPhone项目中,我实际上是手动执行此操作的。希望看到答案。
Jacob Relkin'5

Answers:


261
print(__FUNCTION__) // Swift
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C

Swift 3及以上

print(#function)

120
如果要使用NSLog(@"%@", NSStringFromSelector(_cmd)),您确实应该使用,_cmd因为AFAIK Apple声明_cmd为type SEL,而不是C字符串。仅仅因为它恰好被实现为C字符串(从Mac OS X和iPhone OS的当前版本开始)并不意味着您应该以这种方式使用它,因为Apple可以在OS更新中对其进行更改。
尼克·福奇

5
是的,NSStringFromSelector是更正确的答案。除了调试代码,我从不将_cmd用作c字符串。
2010年

哇,编译器抱怨指针不兼容,但是它可以工作...所以_cmd(类型:SEL)确实是 char * !?
Nicolas Miari 2012年

3
像方法调用一样[self doSomething:arg1 somethingElse:arg2]转换为C函数调用objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);。的第二个参数objc_msgSend()需要char*。请记住,由于Objective-C运行时是动态的,因此它实际上是使用查找表来找出要在哪个类上调用的方法,因此char *十分方便,因为方法在查找表中以字符串表示。
杰克·劳伦斯

1
对于Swift 2.2,应该使用print("\(#function)")
Jake Lin

161

要从技术上回答您的问题,您需要:

NSLog(@"<%@:%@:%d>", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__);

或者,您也可以这样做:

NSLog(@"%s", __PRETTY_FUNCTION__);

2
__FUNCTION__C函数相当的同等功能。
Georg Fritzsche 2010年

NB __FUNCTION__还包括班级名称
OrangeDog

1
使用NSLog(@“%s”,_func_)有什么区别;或NSLog(@“%s”,_PRETTY_FUNCTION_)???
拉维

83

tl; dr

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

细节

Apple有一个“技术问答”页:QA1669-如何在我的日志记录语句中添加上下文信息(例如当前方法或行号)?

为了协助记录:

  • C预处理器提供了一些
  • Objective-C提供表达式(方法)。
    • 隐式参数传递给当前方法的选择器:_cmd

如其他答案所示,仅获取当前方法的名称,请调用:

NSStringFromSelector(_cmd)

要获取当前方法名称当前行号,请使用以下两个宏__func____LINE__如下所示:

NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);

另一个例子……我保存在Xcode的代码片段库中的代码片段:

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

…和TRACE而不是ERROR…

NSLog( @"TRACE %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

…还有较长的代码使用传递值([rows count])的软编码描述…

NSLog( @"TRACE %@ METHOD %s:%d.", [NSString stringWithFormat:@"'Table of Contents.txt' file's count of Linefeed-delimited rows: %u.", [rows count]] , __func__, __LINE__ );

用于记录的预处理器宏

请注意在宏的两边使用一对下划线字符。

| 宏| 格式| 描述
  __func__%s当前函数签名
  __LINE__%d当前行号
  __FILE__%s源文件的完整路径
  __PRETTY_FUNCTION__%s类似于__func__,但包含详细信息
                                    在C ++代码中键入信息。 

记录表达式

| 表达| 格式| 描述
  NSStringFromSelector(_cmd)%@当前选择器的名称
  NSStringFromClass([self class])%@当前对象的类名
  [[NSString%@源代码文件名
    stringWithUTF8String:__ FILE__]   
    lastPathComponent] 
  [NSThread callStackSymbols]%@堆栈跟踪的NSArray

记录框架

一些日志记录框架也可能有助于获取当前的方法或行号。我不确定,因为我在Java中使用了很棒的日志记录框架(SLF4J + LogBack),但没有使用Cocoa。

请参阅此问题以获取指向各种Cocoa日志记录框架的链接。

选择器名称

如果您有一个Selector变量(SEL),则可以按照此Codec 博客文章中所述的两种方法之一打印其方法名称(“消息”):

  • 使用Objective-C调用NSStringFromSelector
    NSLog(@"%@", NSStringFromSelector(selector) );
  • 使用直线C:
    NSLog(@"%s", selector );

该信息来自于2013-07-19的链接的Apple文档页面。该页面的最新更新时间为2011-10-04。


1
对于C,请使用sel_getName(SEL)SEL ,因为SEL是不透明的,并且不一定总是char *
Ethan Reesor 2013年

8
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
print(__FUNCTION__) // Swift

4
对于以后遇到此答案的任何人:它等同于已接受的答案,但是在发布此答案时(已接受的答案于2014年进行了编辑),已接受的答案有所不同。我本来打算投反对票,但经过一小段调查后投了反对票:)
FreeNickname 2015年

0

实际上就像这样简单:

printf(_cmd);

出于某种原因,iOS允许_cmd作为文字字符传递,甚至没有编译警告。谁知道


0

在Swift 4中:

func test(){

print(#function)

}

test()//打印值“ test()”

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.