如何防止自定义 init 方法泄露 Xcode 中的绝对源路径?

How to prevent a custom init method from revealing the absolute source path in Xcode?

对于一个新的 Xcode 项目,我以这种方式添加了一个带有自定义初始化方法的新 class:

import Cocoa

class NewClass: NSControl {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

但是,如果我构建并存档项目,二进制文件中会显示源文件的绝对路径:

/Users/my_username/my_path_to_xcode_projects/new_project/NewClass.swift

我打算在 Internet 上发布我的期末项目。如何防止 Xcode 将我的目录布局透露给他人?我从类似问题的答案中了解到,在 Xcode 的 "Build Settings" 中,应该将 "Deployment Prostprocessing" 设置为 Yes 以便从二进制文件中删除符号,但这在我的情况下似乎不起作用.

如果你仔细看fatalError的签名:

@noreturn public func fatalError(
    @autoclosure message: () -> String = default, 
    file: StaticString = #file, line: UInt = #line)

您可以看到 #file#line 默认参数。这些在编译时进行评估并解析为当前文件和行。

不使用默认参数,您可以自己提供:

fatalError("Something went wrong", file: "", line: 0)

在发布配置上编译时,路径不包含在二进制文件中。

如果您在标准库中搜索 #file,您可以找到其他 4 个实例,其中两个是 assertassertionFailure,它们不会包含在版本中建造。剩下的 2 个是 preconditionpreconditionFailure.

解决方法

如果我们add the DEBUG/RELEASE symbols

我们可以对模拟 fatalError 等函数进行条件编译,这些函数在发布版本中不使用 #file 预处理器语句:

#if RELEASE
@inline(__always) @noreturn func fatalError(@autoclosure message: () -> String = "") {
    Swift.fatalError(message, file: "", line: 0)
}
    
@inline(__always) func preconditionAlt(@autoclosure condition: () -> Bool, @autoclosure _ message: () -> String = "") {
    Swift.precondition(condition, message, file: "", line: 0)
}

@inline(__always) @noreturn func preconditionFailureAlt(@autoclosure message: () -> String = "") {
    Swift.preconditionFailure(message, file: "", line: 0)
}
#else
@inline(__always) func preconditionAlt(@autoclosure condition: () -> Bool, @autoclosure _ message: () -> String = "", file: StaticString = #file, line: UInt = #line) {
    Swift.precondition(condition, message, file: file, line: line)
}

@inline(__always) @noreturn func preconditionFailureAlt(@autoclosure message: () -> String = "") {
    Swift.preconditionFailure(message, file: file, line: line)
}
#endif

您调用这些函数的所有实例现在都使用自定义实现。这样您在调试时仍然可以获得文件和行信息,但可以防止它出现在产品中。但是,您必须将 precondition[Failure] 的每个实例更改为 precondition[Failure]Alt,否则 Swift 无法明确推断该函数。你可以按Shift-Alt-Cmd-F在整个项目中搜索和替换

备注

如果第三方框架使用了这些函数,而你在自己的机器上编译,那么路径显然会包含在框架产品中。为防止这种情况,您要么必须使用预编译版本,要么使用模拟自行编译。

如果任何其他自声明或第三方函数使用 #file,您显然也必须更改它,虽然这不是很常见。

可能还有其他我不知道的文件结构泄露的可能性。