【问题标题】:NSLog the method name with Objective-C in iPhoneNSLog iPhone中Objective-C的方法名
【发布时间】:2011-02-15 18:02:54
【问题描述】:

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

#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 调试器,但有时我也想通过注销来进行调试。

【问题讨论】:

标签: objective-c c iphone debugging


【解决方案1】:
print(__FUNCTION__) // Swift
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C

Swift 3 及以上版本

print(#function)

【讨论】:

  • 如果你打算使用_cmd,你真的应该使用NSLog(@"%@", NSStringFromSelector(_cmd)),因为AFAIK Apple 将_cmd 声明为SEL 类型,而不是C 字符串。仅仅因为它恰好被实现为 C 字符串(从 Mac OS X 和 iPhone OS 的当前版本开始)并不意味着您应该以这种方式使用它,因为 Apple 可以在 OS 更新中更改它。
  • 是的,NSStringFromSelector 是更正确的答案。除了调试代码,我从不使用 _cmd 作为 c 字符串。
  • 哇,编译器抱怨指针不兼容,但它可以工作......所以 _cmd (type: SEL) 真的是 char* !?
  • [self doSomething:arg1 somethingElse:arg2] 这样的方法调用被转换为C 函数调用objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);objc_msgSend() 的第二个参数采用 char*。请记住,由于 Objective-C 运行时是动态的,它实际上使用查找表来确定要调用哪个类的哪个方法,因此 char* 很方便,因为方法在查找表中表示为字符串。
  • 对于 Swift 2.2 应该使用 print("\(#function)")
【解决方案2】:

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

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

或者你也可以这样做:

NSLog(@"%s", __PRETTY_FUNCTION__);

【讨论】:

  • 使用 __FUNCTION__ 和它的相当等价物也可以在 C 函数中使用。
  • 注: __FUNCTION__ 还包括类名
  • 使用 NSLog(@"%s",_func_); 有什么不同吗?或 NSLog(@"%s", _PRETTY_FUNCTION_) ???
【解决方案3】:

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

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

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__] 最后路径组件] [NSThread callStackSymbols] %@ NSArray 的堆栈跟踪

日志框架

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

有关各种 Cocoa 日志框架的链接,请参阅 this question

选择器名称

如果您有一个 Selector 变量(SEL),您可以按照此 Codec blog post: 描述的两种方式之一打印其方法名称(“消息”): p>

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

此信息取自截至 2013 年 7 月 19 日的链接 Apple 文档页面。该页面上次更新时间为 2011 年 10 月 4 日。

【讨论】:

  • 对于 C,请使用 sel_getName(SEL),因为 SEL 是不透明类型,可能并不总是 char *
【解决方案4】:
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
print(__FUNCTION__) // Swift

【讨论】:

  • 对于将来遇到此答案的任何人:它等同于已接受的答案,但在发布此答案时已接受的答案不同(已在 2014 年编辑了已接受的答案)。我正要投反对票,但经过一个小调查后,我投了赞成票:)
【解决方案5】:

其实很简单:

printf(_cmd);

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

【讨论】:

    【解决方案6】:

    在 Swift 4 中:

    函数测试(){

    print(#function)
    

    }

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多