代码之家  ›  专栏  ›  技术社区  ›  stk

Swift中是否有前缀头(或具有此功能的东西)?

  •  9
  • stk  · 技术社区  · 9 年前

    有没有办法在Swift中获得前缀头的功能?我不想在使用外部库的每个文件中导入外部库。

    4 回复  |  直到 9 年前
        1
  •  42
  •   peterh Eli    3 年前

    不,但你不需要它,没有成本 import UIKit 除了键入12个字符所需的时间之外。(或者使用已经有它们的Xcode New File模板。)

    这就是TLDR。关于整个故事,请继续阅读。。。


    在(Obj)C中,使API可用于源代码文件的旧方法是 文本包含 。预处理器将看到 #import <Foundation/Foundation.h> 指令和 复制所有文本 在将其传递给编译器之前,将该头文件(以及它包含的任何其他头文件,以及它们包含的头文件等)转换为源文件。正如您所期望的,重新编译数千行系统头声明 对于项目中的每个文件 没有那么出色。

    所以,几年前我们得到了预编译的头文件,你可以把 #import 这些部分的编译步骤只需完成一次,这样编译器后端就可以为项目中的每个文件重用。但这也有它的问题:保持PCH正常运行有维护负担,而且它不允许您限制每个源文件中使用的名称空间(即,如果您需要一个 .m 文件,只看到它需要使用的符号,而不是项目中其他地方使用的所有其他东西)。

    除此之外,文本包含还有一个潜在的脆弱性问题。如果你 #define 高于你的 #进口 行,并且定义了导入头中使用的符号的更改,这些头将有编译错误(或以更微妙的方式失败,如定义错误的API)。有一些惯例可以防止这种情况发生,但惯例并没有强制执行,你总是一个打字错误/新的团队成员/糟糕的合并,远离一切崩溃。

    无论如何,即使是预编译的头文件,文本包含也不是很好,所以在Xcode 5中,苹果引入了 模块 (事实上,不仅仅是苹果。 They're in the LLVM/Clang compiler suite, so they're open source. )模块基于 语义导入 ,而不是文本包含,也就是说,模块在抽象级别告诉编译器它为源代码提供了哪些API符号,而不是将这些符号的定义粘贴在文本中,这样它们就不会脆弱,而且它们在后端单独预编译,这样构建项目就可以保持快速。

    模块现在是ObjC项目的默认模块。(请注意,如果您创建了一个新的ObjC项目,它将不再包含预编译头。您可以关闭模块,因此如果您有一个旧项目,您可能仍然使用文本包含和预编译的头。)您可以在 Session 404 from WWDC 2013 .


    为什么所有这些关于ObjC的事情?我们说的是斯威夫特,对吧?嗯,Swift基于很多相同的基础设施。

    Swift从一开始就使用模块,所以它总是基于语义导入。这意味着构建时性能不会受到影响,也不会出现脆弱性。所有的斯威夫特 import 所做的就是告诉编译器你需要什么符号(以及在生成二进制可执行文件时链接器在哪里找到它们)。

    所以唯一的成本是 进口 s在每个文件的顶部是打字。在Swift中,这是一个必要的成本,源文件是一个语义单元,决定其中包含什么是真正的意义 import Foundation ,如果您的应用程序中有一部分希望严格使用Swift集合和值类型,那么您可能不想导入Foundation(或Cocoa或UIKit或其他包含它的东西),以实现与Cocoa集合和值的桥接。


    更新: 此外,您的选择 进口 在Swift文件中有真正的意义。

    例如,编译器如何优化泛型和静态/动态分派取决于给定文件中可见的声明,因此如果 进口 比您需要的更多,您可能会生成更慢的代码。因此,一般来说,最好 进口 只有你需要的。

    显式导入也有助于提高清晰度和可读性。如果 进口 当你将粘贴代码从一个项目复制到另一个项目时,你会在新位置看到很多错误。。。而这就不太清楚了 进口 你需要解决这些问题。


    “但我讨厌把同样的几个 进口 你说:“我们一直在每个文件的顶部。”。

    • 你真的需要吗 几个 ? 大多数模块过渡 进口 它们的依赖性。你不需要 导入基础 如果你已经 进口 ing Cocoa(OS X)或UIKit(iOS/tvOS/watchOS)。例如,如果你正在编写SpriteKit或SceneKit游戏,你会自动免费获得UIKit/Cocoa(适用于任何平台)和Foundation。

    • 你真的需要同样的吗 在每个文件中 ? 当然,你在一个UIKit项目中,所以你几乎到处都在使用UIKit。但这只是一个 进口 ,顶部有十二个字符。也许你的项目也在使用联系人或照片或CoreBluetooth或HealthKit。。。但它可能不需要在您定义的每个类型中使用所有这些。(如果是这样,您的代码可能会受到关注点分离不良的影响。)

    • 你真的在管理吗 进口 声明 总是 ? 我不知道你的项目,但在我从事过的大多数大型项目中,我认为至少90%的开发活动涉及编辑现有的源文件,而不是创建新的源文件。。。在开始项目或主要功能的工作后,我们很少(重新)定义源文件集或它们的依赖项。还有一些快捷方式可以帮助(除其他外)设置导入,例如 Xcode file templates .

        2
  •  20
  •   Community Dai    7 年前
    1. 创建 Objective-C桥接标头 文件:

      [新建文件iOSSourceHeader文件]: Bridging-Header.h

    2. 转到此新标题并导入外部库:

      @import Module1Name;
      @import Module2Name;
      ...
      
    3. 生成设置 ,设置的路径 Objective-C桥接标头 :

      [TargetBuild SettingsSwift编译器-代码生成Objective-C桥接头]: $(SRCROOT)/.../Bridging-Header.h

    然后,您可以在每个文件中使用外部库,而无需 import 密码


    参考文献:

        3
  •  0
  •   Nike Kov    7 年前

    There 是一个 -enable-bridging-pch 特色但似乎无法在Xcode 9中工作:(
    我决定写这篇回答,只是为了完全涵盖这个话题。

        4
  •  0
  •   Cy-4AH    4 年前

    您可以创建将导入依赖项的模块,并仅导入它。

    例如呼叫 Core 。它将只包含一个带有导入的swift文件。

    每次导入都应以开头 @_exported 关键字。

    例如:

    @_exported import UIKit;
    @_exported import Combine;