我对 Swift 语言很陌生。
我想声明一个内联函数,就像在C++所以我的func
声明看起来像这样:
func MyFunction(param: Int) -> Int {
...
}
我想做这样的事情:
inline func MyFunction(param: Int) -> Int {
...
}
我尝试在网上搜索,但没有找到任何相关的东西,也许没有inline
关键字,但也许还有另一种方法可以在 Swift 中内联函数。
Swift 1.2 将包含 @inline
属性,never
和 __always
作为参数。有关详细信息,请参阅此处。
如前所述,你很少需要将函数显式声明为 @inline(__always)
因为 Swift 在何时内联函数方面相当聪明。但是,在某些代码中,没有内联函数可能是必需的。
Swift-5 添加了 @inlinable
属性,这有助于确保库/框架内容对于链接到库的内容是可内联的。请务必阅读有关它的信息,因为可能有几个陷阱可能会使其无法使用。它也只适用于声明public
的函数/方法,因为它适用于想要公开内联内容的库。
所有功劳都归功于答案,只是总结了链接中的信息。
要使函数内联,只需在函数之前添加@inline(__always)
:
@inline(__always) func myFunction() {
}
但是,值得考虑和了解不同的可能性。有三种可能的内联方法:
- 有时 - 将确保有时内联函数。这是默认行为,您无需执行任何操作!Swift 编译器可能会自动内联函数作为优化。
- 总是 - 将确保始终内联函数。通过在函数之前添加
@inline(__always)
来实现此行为。使用"如果你的函数相当小,并且你希望你的应用运行得更快"。 - 从不 - 将确保永不内联函数。这可以通过在函数之前添加
@inline(never)
来实现。使用"如果您的函数很长,并且您希望避免增加代码段大小"。
我遇到了一个问题,我需要使用 Swift 4.2 中引入的@inlinable
和@usableFromInline
属性,所以我想与您分享我的经验。
让我直接进入这个问题,我们的代码库有一个链接其他模块的分析外观模块。
应用目标 -> 分析外观模块 -> 报告模块 X。
分析外观模块具有一个名为report(_ rawReport: EventSerializable)
的函数,用于触发报告调用,此函数使用报告模块 X 中的实例发送该特定报告模块 X 的报告调用。
问题是,一旦用户启动应用程序,多次调用该report(_ rawReport: EventSerializable)
函数来发送报告呼叫会产生不可避免的开销,这给我们带来了很多崩溃。
此外,如果要将Optimisation level
设置为在调试模式下None
,则重现这些崩溃并非易事。就我而言,我只能在将Optimisation level
设置为 Fastest, Smalles
t 甚至更高时重现它。
解决方案是使用 @inlinable
和 @usableFromInline
.
@inlinable
和 @usableFromInline
将函数体导出为模块接口的一部分,以便在从其他模块引用时可供优化器使用。
@usableFromInline
属性将内部声明标记为模块二进制接口的一部分,允许从@inlinable
代码使用它,而无需将其公开为模块源接口的一部分。
跨模块边界,运行时泛型引入了不可避免的开销,因为必须在函数之间传递化类型元数据,并且必须使用各种间接访问模式来操作泛型类型的值。对于大多数应用程序,与代码本身执行的实际工作相比,此开销可以忽略不计。
基于此框架构建的客户端二进制文件可以调用这些泛型函数,并且在启用优化的情况下构建时,由于消除了抽象开销,因此可以提高性能。
示例代码:
@inlinable public func allEqual<T>(_ seq: T) -> Bool
where T : Sequence, T.Element : Equatable {
var iter = seq.makeIterator()
guard let first = iter.next() else { return true }
func rec(_ iter: inout T.Iterator) -> Bool {
guard let next = iter.next() else { return true }
return next == first && rec(&iter)
}
return rec(&iter)
}
更多信息 - 跨模块内联和专业化
我来这里是因为我正在寻找一种出于安全原因混淆代码的方法.
内联敏感方法可能会使从编译的二进制文件中获取敏感信息变得更加困难。
我在本文中找到了该主题的一个很好的摘要:swift 中的禁止内联属性
作者建议一般不要使用@inline
因为决定应该留给编译器做出,而且它甚至没有得到官方支持><。但是,它也列出了一些@inline
可能有益的边缘情况,例如优化速度或代码混淆。