Buildable Folder & Group & Folder Reference in Xcode

0 阅读4分钟

深入理解代替单纯记忆

问题背景

  • 在开发iOS项目时,希望将一堆图片资源放入Main Bundle中,但又不希望资源在Bundle的最顶层目录中,希望自定义目录
  • 但一时想不到该如何解决,于是想到FolderGroup等概念
  • 经过简单搜索后,发现Xcode对于这两个概念的定义还是有些差异的
  • 于是继续查阅学习了一番,编写本文,方便后续查阅和分享

本文提到的内容,参考的Xcode版本为26.0(17A324)和26.3(17C529)

Buildable Folder

  • Buildable Folder是自Xcode 16(2024年6月)引入的概念,初衷是为了减少代码管理中的冲突问题
  • 后续新建的工程或者新建Folder时,默认都是Buildable Folder

官方原文如下:

Minimize project file changes and avoid conflicts with buildable folder references. Convert an existing group to a buildable folder with the Convert to Folder context menu item in the Project Navigator. Buildable folders only record the folder path into the project file without enumerating the contained files, minimizing diffs to the project when your team adds or removes files, and avoiding source control conflicts. To use a folder as an opaque copiable resource, the default behavior before Xcode 16, uncheck the Build Folder Contents option in the File Inspector.

Buildable Folder如何降低代码冲突

  1. 先添加1个普通Group--BuildableFolderTest,project文件的变化如下所示: image.png

  2. 然后向BuildableFolderTest Group中添加ABC.swift文件后,project文件的变化如下: image.png image.png

    这说明Group目录下的文件,都要在project文件中进行记录

  3. 继续,将BuildableFolderTest Group通过Convert to Folder选项转为Folder(Buildable Folder)后,project文件的变化如下: image.png image.png

  4. 然后再向BuildableFolderTest这个Folder中添加DEF.swift文件后,发现project文件没有任何变化

所以,project文件仅记录了Folder自身,至于目录中的文件是不会记录在project文件中,所以会减少因团队多人同时修改Project文件导致的代码冲突

Apply to Each File vs Apply Once to Folder

当创建Folder(Buildable Folder)后,选中Folder,在File inspector中会看到有个Build Rule,有两个选择:Apply to Each FileApply Once to Folder,默认是Apply to Each File

image.png

Apply Once to Folder

Apply Once to Folder开启后,project文件是什么样?

image.png image.png image.png

当开启该模式时,通过查看目录下的每个文件可以看出,文件是没有Target归属的概念的。同样,在该目录下创建新文件也不需要选择Target

再配合Xcode Buildable Folders中所提到的To use a folder as an opaque copiable resource, the default behavior before Xcode 16, uncheck the Build Folder Contents option in the File Inspector.

其实,Apply Once to Folder就是Xcode 16之前的Folder,之前叫Folder Reference (在Xcode 16之前,创建Folder时,官方名称就叫做Folder Reference)

  • Folder Reference一般是用作资源包,目录下不包含源代码
  • 另一个Folder Reference重要作用是可以在Bundle中自定义目录

Buildable Folder vs Folder Reference

Buildable Folder顾名思义,其中的内容是由编译系统参与的

  • 所以Buildable Folder中可以放源代码文件,并可以参与编译,打包到最终可执行文件中;也可以制定源文件的Target
  • Folder Reference则保留老的逻辑,不参与编译,用作资源包,即使放入源代码文件也无法选择Target,只能当做普通文件资源处理

Create Group with Folder

同样是在Xcode 16开始的另一个变化是,创建Group时由原来的不自动创建磁盘物理目录(Folder)变为自动创建。当然,仍可以创建没有FolderGroup,原文如下:

Create groups with associated folders by default when using the New Group and New Group from Selection commands in the Project Navigator. To create a group without a folder, hold the Option key in the context menu to reveal the New Group without Folder variant of the command.

[Group without Folder] vs [Group] vs [Folder(Buildable Folder)] vs [Folder Reference]

特性Group without FolderGroupBuildable FolderFolder Reference
Project Navigator 图标image.pngimage.pngimage.pngimage.png
是否对应磁盘目录❌ 不必须✅ 必须✅ 必须✅ 必须
工程结构是否可与磁盘不同✅ 可以❌ 基本一致❌ 必须一致❌ 必须一致
.pbxproj 是否记录每个文件✅ 会✅ 会❌ 不会❌ 不会
新增文件是否修改 .pbxproj✅ 会✅ 会❌ 不会❌ 不会
Git 冲突概率
是否参与编译系统
是否自动编译源码✅(自动发现目录中的源码)
Bundle 中是否保留目录结构❌ 通常不会❌ 通常不会❌ 通常不会会保留(如果被加入 Bundle)
默认是否进入 Bundle❌ 否❌ 否❌ 否仅在选中 Target 时自动加入
典型用途逻辑分组常规项目结构源码目录资源目录
  • 当前(Xcode 26),默认的Group和Folder组合是Group with Folder + Buildable Folder。这可能也意味着这两项是日常最常用的

回答开始的问题

  • 既然是想打包资源放入Bundle,并自定义目录,那必然是Folder Reference

参考