Swift条件编译&x27;使用objective-c中定义的宏时,无法正常工作

Swift条件编译&x27;使用objective-c中定义的宏时,无法正常工作,objective-c,swift,Objective C,Swift,我在objective-c头文件中定义了一个简单的宏,并通过项目桥接头文件将该头文件导入Swift。我可以在Swift中将此宏用作常量,但当我使用它进行条件编译时,它无法正常工作 我在Xcode 10.2.1中创建了一个简单的项目,并添加了一些代码来重现它。 在ViewController.h中 #定义测试标志1 @界面ViewController:UIViewController @结束 在ViewController.m中 #import "testMacro-Swift.h" - (v

我在objective-c头文件中定义了一个简单的宏,并通过项目桥接头文件将该头文件导入Swift。我可以在Swift中将此宏用作常量,但当我使用它进行条件编译时,它无法正常工作

我在Xcode 10.2.1中创建了一个简单的项目,并添加了一些代码来重现它。 在ViewController.h中

#定义测试标志1
@界面ViewController:UIViewController
@结束
在ViewController.m中

#import "testMacro-Swift.h"

- (void)viewDidLoad {
    [super viewDidLoad];

    SwiftClass *s = [[SwiftClass alloc] init];
    [s printMSG];

#if TEST_FLAG
    NSLog(@"Objc works.");
#endif
}
在testMacro桥接Header.h中

#import "ViewController.h"
快捷文件

@objc class SwiftClass: NSObject {
    @objc func printMSG() {
        print("Macro \(TEST_FLAG)")
        #if TEST_FLAG
        print("compiled XXXxXXXXX")
        #endif
    }
}
控制台输出

Macro 1
2019-07-03 14:38:07.370231-0700 testMacro[71724:11911063] Objc works.
我希望编译后的XXXxXXXXX会在宏1之后打印,但事实并非如此

我很好奇为什么会发生这种情况。
我的项目混合了objc和swift。我不想在swift中声明相同的标志。

基于这篇苹果文章,简单C(和Objective-C)宏作为全局常量导入swift。这可以通过生产线的输出来证明

print("Macro \(TEST_FLAG)")
片段

    #if TEST_FLAG
    print("compiled XXXxXXXXX")
    #endif
使用不同的
测试标志
,这是一个Swift预处理器标志。您可以在生成设置->活动编译条件下将其定义为
TEST\u FLAG
,或者在生成设置->其他Swift标志下将其定义为
-DTEST\u FLAG

以上解释了为什么会发生这种情况。我想不出一个简单的方法来避免在Xcode中分别为Objective-C和Swift预处理器定义相同的标志。如果您只想根据
TEST\u标志
控制是否执行某些Swift代码,可以执行以下操作:

if TEST_FLAG != 0 {
        print("compiled XXXxXXXXX")
}
但是,如果您想要控制代码的编译,那么您可能必须对Objective-C和Swift使用单独的
TEST_标志
s,并确保它们一致。为了帮助它们保持一致,您可以在
其他C标志
中设置Objective-C代码使用的
测试标志
,这允许您为不同的SDK、体系结构和构建类型(发布/调试)定义不同的标志。活动编译条件允许同样的灵活性

促进(目标-)C和Swift编译器标志之间一致性的另一个技巧是创建一个新的用户定义的生成设置:单击“生成设置”下搜索框左侧的
+

比方说,将其称为
COMMON\u TEST\u FLAG
,并将其值设置为
TEST\u FLAG
。然后将
-D$(公共测试标志)
添加到其他C标志和其他Swift标志。现在,当您构建代码时,
TEST\u标志
将在目标中的Objective-C和Swift代码中定义。如果不想定义它,只需将
COMMON\u TEST\u FLAG
的值更改为其他值即可。不过,有几件事需要注意:

  • 不能将
    COMMON\u TEST\u标志
    设为空:这将导致另一个 标记为-D,导致生成错误
  • 确保
    COMMON\u TEST\u标志的值与
    在别处定义的宏
Swift的预处理器(有意地)比C的更有限。宏具有非常严重的回退

  • 它们定义了在每个构建目标中不活动的代码区域。因此,您的测试不会命中每个分支(甚至不会编译每个分支)。这很快就会成为维护灾难。对于
    n
    唯一标志,有2^n
    可能的值集,因此,
    2^n`可能的构建。你必须测试每一个吗?也许,也许不是,但即使只是对测试内容进行推理也不容易

  • 它们可能会纠结在一起,非常复杂,尤其是嵌套块

  • 一般来说,尽量用主编程语言(C、ObjC、Swift)来表达代码,只有在有充分理由的情况下才使用宏,例如:

  • 以函数无法实现的方式减少重复
  • 提高关键代码区域的性能(通过强制宏代码内联,例如
    #define max(a,b)((a)<(b)?(b):(a))
    )。虽然这是非常罕见的
  • 表达一段无法用语言表达的逻辑。例如,如果在Swift中可用(…),则在不使用预处理器的情况下无法表示
  • 您的示例不符合这些标准中的任何一个。它增加了重复性,对性能没有要求,也没有做常规Swift代码无法完成的事情


    一种更好的方法(在Swift和Objective C中)是创建一个记录器,该记录器在调试和发布版本之间使用不同的配置进行初始化。您的
    viewDidLoad
    方法不应该关心是否设置了
    TEST\u标志。视图控制器应该控制视图,而不是决定应该记录哪些内容。它应该只调用记录器发送它想要发送的任何日志消息,并让记录器决定如何记录这些消息(到输出流、文件、内存循环缓冲区、数据库、流到分析API、忽略它们等)

    我确实在桥接头中导入objc文件。您可以看到
    print(“Macro\(TEST\u FLAG)”)
    运行,并打印正确的TEST\u FLAG,但这不是条件编译,这就是问题所在。对不起,您是对的,@matt。我读这个问题太匆忙了。修改了答案。