【问题标题】:Is there any way I can tell from what class/method a method is called?有什么方法可以告诉我从哪个类/方法中调用了一个方法?
【发布时间】:2016-05-18 18:10:09
【问题描述】:

我有一个像这样使用的预处理器宏:

@implementation MyClass
- (void)methodA
{
    MyLog("Hello, method A!");
}

- (void)methodB
{
    MyLog("Hello, method %@!", @"B");
}
@end

宏展开后的样子:

@implementation MyClass
- (void)methodA
{
    ; NSLog([NSString stringWithFormat:@"%s - %@", __func__, "Hello, method A!"]); ;
}

- (void)methodB
{
    ; NSLog([NSString stringWithFormat:@"%s - %@", __func__, "Hello, method %@!"], @"B"); ;
}
@end

这将导致这些被打印为各自的方法:

-[MyClass methodA] - Hello, method A!
-[MyClass methodB] - Hello, method B!

我想将其更改为一组 Objective-C 或 Swift 方法,我可以用相同的方式调用它们,并得到相同的结果。我不想管理一个对象,所以这些应该是类/静态方法。 是否可以告诉我我在一个特定的类/方法中并且只在其中使用特定的日志前缀?

如果没有,有没有其他方法可以使用方法来模仿我通过宏实现的行为?

【问题讨论】:

  • 试试看here (objective-c),你应该会找到你要找的东西(除非我误解了)。您可以根据您的构建上下文(调试与发行版)自动为此定义宏。
  • 分号是什么鬼?不要那样做。
  • @AMomchilov 这些是因为宏在它们的语句之前和之后都有一个分号(以防止扩展语法错误;使用 do { ... } while(0) 的原因相同)。因此,当我输入带有分号的宏时,所有三个都以扩展形式出现。
  • @YvesLeBorg 似乎只是打印出日志方法的名称:P

标签: objective-c swift c-preprocessor


【解决方案1】:

这里你想要的 Swift 工具一般是#function。例如:

func MyLog(msg: String, function: StaticString = #function) {
    print("\(function) - \(msg)")
}

#function,当用作默认参数值时,计算结果为调用站点处的函数。由于它是默认值,因此您不必传递 function 参数。

但是,这与 ObjC 不兼容。为此,您仍然需要宏。如果您想将 ObjC 宏转发到 Swift,您可以执行以下操作:

#define MYLog(message) [Log log:message function:@(__FUNCTION__)]

然后你需要这样写MyLog

struct Log {
    static func log(msg: String, function: String = #function) {
        // ...
    }
}

它必须在 struct 中才能被 ObjC 访问(或者它可以是一个枚举),并且你必须使 function 类型为 String 而不是 StaticString 因为 ObjC 无法生成StaticString.

像这样构建,在 Swift 中,你会调用:

Log.log("my message")

在 ObjC 中你会调用

MyLog("my message")

【讨论】:

  • 这看起来很棒。不过,我不清楚一件事;是否可以从 ObjC 实际调用MyLog?如果有,怎么做?
  • 对不起;我的原始代码有一个奇怪的 ObjC/Swift 废话混合体。固定。
  • @RobNapier:这太棒了!我不知道这种技术。
  • 太棒了;我会在第一时间尝试一下
【解决方案2】:

我(通过宏扩展)产生了类似的结果。

在 GERuntimeConstants.h 中,我定义了

extern void QuietLog(NSString *format, ...);

在 GERuntimeConstants.m 中,我提供 QuietLog 为:

void QuietLog(NSString *format, ...) {

    if (format == nil) {
        printf("nil\n");
        return;
    }
    // Get a reference to the arguments that follow the format parameter
    va_list argList;
    va_start(argList, format);
    // Perform format string argument substitution, reinstate %% escapes, then print
    NSString *s = [[NSString alloc] initWithFormat:format arguments:argList];
    printf("%s\n", [[s stringByReplacingOccurrencesOfString:@"%%" withString:@"%%%%"] UTF8String]);
    va_end(argList);
}

在 GEMacros 中,我定义了

#define __MPLOGWITHFUNCTION(s, ...) \
QuietLog(@"%s : %@",__FUNCTION__,[NSString stringWithFormat:(s), ##__VA_ARGS__])  
#define MPLOG(...) __MPLOGWITHFUNCTION(__VA_ARGS__)

我在我的 .pch 中包含 GEMacros.h

在我想登录的任何地方,我都会有一行代码,如下例所示:

- (void)cleanupWithError:(NSString *)status message:(NSString *)message {
      MPLOG(@"*** Cleaning up , status[%@], message[%@]",status,message);

这个语句在控制台中翻译成这个:

-[EHRCall cleanupWithError:message:] : *** Cleaning up , status[INVALID_PARAMETERS], message[No api user with api key [patient01ApiKey]]

所以在我的代码中,我使用 MPLOG 作为 NSLog(总是)。通过 _MPLOGWITHFUNCTION 的定义是因为我有其他针对构建进行了调整的宏。此定义用于在进行调试构建时进行日志记录。对于发行版 MPLOG 定义为 ;

【讨论】:

  • 啊,错过了...我肯定不会辩论。我天生懒惰,并且喜欢能够更改一个编译标志来翻转我的一些throw-away 代码(如日志记录)。
  • 这当然是 C 语言的一个很棒的特性。但是,我们正在尝试让我们的代码与 Swift 兼容,如果不仅仅是 Swift 的话。
猜你喜欢
  • 2021-09-21
  • 1970-01-01
  • 2012-06-29
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多