当我使用 Objective-c 中定义的宏时,Swift 条件编译无法正常工作

Kan*_*hen 3 objective-c swift

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

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

#define TEST_FLAG 1

@interface ViewController : UIViewController
@end
Run Code Online (Sandbox Code Playgroud)

在 ViewController.m 中

#import "testMacro-Swift.h"

- (void)viewDidLoad {
    [super viewDidLoad];

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

#if TEST_FLAG
    NSLog(@"Objc works.");
#endif
}
Run Code Online (Sandbox Code Playgroud)

在 testMacro-Bridging-Header.h 中

#import "ViewController.h"
Run Code Online (Sandbox Code Playgroud)

快速文件

@objc class SwiftClass: NSObject {
    @objc func printMSG() {
        print("Macro \(TEST_FLAG)")
        #if TEST_FLAG
        print("compiled XXXxXXXXX")
        #endif
    }
}
Run Code Online (Sandbox Code Playgroud)

控制台输出

Macro 1
2019-07-03 14:38:07.370231-0700 testMacro[71724:11911063] Objc works.
Run Code Online (Sandbox Code Playgroud)

我希望compiled XXXxXXXXX在 之后打印Macro 1,但事实并非如此。

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

Ana*_*i P 5

根据这篇 Apple 文章https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_macros_in_swift,简单的 C(和 Objective-C)宏作为全局常量导入到 Swift 中。您的线路的输出证明了这一点

print("Macro \(TEST_FLAG)")
Run Code Online (Sandbox Code Playgroud)

片段

    #if TEST_FLAG
    print("compiled XXXxXXXXX")
    #endif
Run Code Online (Sandbox Code Playgroud)

使用不同的TEST_FLAG,这是一个 Swift 预处理器标志。您可以在 Build Settings -> Active Compilation Conditions 下将其定义为TEST_FLAG或在 Build Settings -> Other Swift Flags 下定义为-DTEST_FLAG

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

if TEST_FLAG != 0 {
        print("compiled XXXxXXXXX")
}
Run Code Online (Sandbox Code Playgroud)

但是,如果您想控制代码的编译,那么您可能必须TEST_FLAG为 Objective-C 和 Swift使用单独的s 并确保它们是一致的。为了帮助使它们保持一致,您可以在 中设置TEST_FLAGObjective-C 代码使用的Other C Flags,这允许您为不同的 SDK、架构和构建类型(发布/调试)定义不同的标志。活动编译条件允许同样的灵活性。

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

说,调用它COMMON_TEST_FLAG并将其值设置为TEST_FLAG。然后添加-D$(COMMON_TEST_FLAG)到其他 C 标志和其他 Swift 标志。现在,当你构建你的代码时,你的TEST_FLAG目标中的 Objective-C 和 Swift 代码都会被定义。如果您不想定义它,只需将 的值更改为其他值COMMON_TEST_FLAG即可。不过,有几点需要注意:

  • 您不能为COMMON_TEST_FLAG空:这将导致其他标志仅为 -D,从而导致构建错误。
  • 确保 的值COMMON_TEST_FLAG不与别处定义的宏冲突。