目前,我们正在为自己定义一个扩展日志机制来打印日志的类名和源行号。
#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
项目中,我实际上是手动完成的。很想看到这个问题的答案。
print(__FUNCTION__) // Swift
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
斯威夫特 3 及以上
print(#function)
要从技术上回答您的问题,您需要:
NSLog(@"<%@:%@:%d>", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__);
或者你也可以这样做:
NSLog(@"%s", __PRETTY_FUNCTION__);
__FUNCTION__
及其相当等价的内容也可用于 C 函数。
__FUNCTION__
还包括类名
tl;博士
NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );
细节
Apple 有一个技术问答页面:QA1669 - How can I add context information - such as the current method or line number - to my logging statements?
协助记录:
C 预处理器提供了一些宏。
Objective-C 提供表达式(方法)。为当前方法的选择器传递隐式参数:_cmd
为当前方法的选择器传递隐式参数:_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__ );
用于记录的预处理器宏
请注意在宏的两侧使用一对下划线字符。
| Macro | Format | Description __func__ %s Current function signature __LINE__ %d Current line number __FILE__ %s Full path to source file __PRETTY_FUNCTION__ %s Like __func__, but includes verbose type information in C++ code.
日志记录表达式
| Expression | Format | Description NSStringFromSelector(_cmd) %@ Name of the current selector NSStringFromClass([self class]) %@ Current object's class name [[NSString %@ Source code file name stringWithUTF8String:__FILE__] lastPathComponent] [NSThread callStackSymbols] %@ NSArray of stack trace
日志框架
一些日志框架也可能有助于获取当前方法或行号。我不确定,因为我在 Java (SLF4J + LogBack) 中使用了一个很棒的日志框架,但不是 Cocoa。
有关各种 Cocoa 日志框架的链接,请参阅 this question。
选择器名称
如果您有一个 Selector 变量(一个 SEL),您可以按此 Codec blog post 所述的两种方式之一打印其方法名称(“消息”):
使用 Objective-C 调用 NSStringFromSelector: NSLog(@"%@", NSStringFromSelector(selector) );
使用直接 C: NSLog(@"%s", selector );
截至 2013 年 7 月 19 日,此信息来自链接的 Apple 文档页面。该页面上次更新时间为 2011 年 10 月 4 日。
sel_getName(SEL)
,因为 SEL 是一种不透明类型,可能并不总是 char *
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
print(__FUNCTION__) // Swift
它实际上很简单:
printf(_cmd);
出于某种原因,iOS 允许 _cmd 作为文字字符传递,甚至没有编译警告。谁知道
在 Swift 4 中:
功能测试(){
print(#function)
}
test() //打印值“test()”
_cmd
,您真的应该使用NSLog(@"%@", NSStringFromSelector(_cmd))
,因为 AFAIK Apple 将_cmd
声明为类型SEL
,而不是 C 字符串。仅仅因为它恰好被实现为 C 字符串(从 Mac OS X 和 iPhone OS 的当前版本开始)并不意味着您应该以这种方式使用它,因为 Apple 可以在 OS 更新中更改它。[self doSomething:arg1 somethingElse:arg2]
这样的方法调用被转换为 C 函数调用objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);
。objc_msgSend()
的第二个参数采用char*
。请记住,由于 Objective-C 运行时是动态的,它实际上使用查找表来确定要调用哪个类的哪个方法,因此 char* 很方便,因为方法在查找表中表示为字符串。print("\(#function)")