.xcodeproj/project.pbxproj を解読する

(2018/01/28 追記)

書いたときから２年半たってXcodeのバージョンも2つあがったけどまだちょこちょこストックしてもらえているので、
Xcode9でのproject.pbxprojと照らし合わせて、記事の内容が古くなっているところ確認しました。

結果、特に構造が変わったところはなかったのでXcode9.1 (9.2じゃなくて申し訳ない)時代でも安心してお読み下さい。

(2019/10/05 追記)

Xcode 11 GM seedで構造に変化がないことを確認しました

(追記おわり)

Xcodeプロジェクトのブラックボックス、`{プロジェクト名}.xcodeproj/project.pbxproj` の中身を読んでみたら意外と読めた。

これで明日からはもう、コンフリクトしてもプロジェクト設定がなんか変になっても怖くない。

# サマリーになってないサマリー

![pbxproj.png](https://qiita-image-store.s3.amazonaws.com/0/27025/3689c2ad-8569-725c-2b30-74e8006386a9.png)

図解って難しい。

以下、順を追って解読。

# 準備

解読対象として、新規にXcodeでプロジェクトを生成してまっさらなproject.pbxprojファイルを作る。

| 項目                     | 設定値        |
|:------------------------|:-------------|
| Product Name            | Example      |
| Organization Name       | yokomotod    |
| Organization Identifier | com.yokomoto |
| Language                | Swift        |
| Device                  | Universal    |
| Use Core Data           | No           |
| Include Unit Tests      | Yes          |
| Include UI Tests        | Yes          |

ファイル全体はgistにおいた。[Example.xcodeproj/project.pbxproj](https://gist.github.com/yokomotod/e0b16307991944440bc4)

(2018/1/28 gistの内容をXcode9.1でのものに更新しました。revesion見るとおもしろい)
(2019/10/05 gistの内容をXcode11 GM seedのものに更新しました)

# アウトライン

予想以上に長い記事になってしまったので、以降の流れを書いてみる。

- まえがき
    - サマリ
    - 準備
    - アウトライン ・・・いまここ
- 前半
    - ファイルの構造を解読する
        - ファイルの構造を解読する
        - フォーマット
        - objects 要素の中身
        - rootObject
        - リンク構造
        - リレーション関係 全体図
- 後半
    - 各クラスの中身の解読
        - ファイルやディレクトリを表すクラス
            - PBXGroup
            - PBXFileReference
            - PBXVariantGroup
        - ターゲットを表すクラス
            - PBXNativeTarget
            - PBXTargetDependency
            - PBXContainerItemProxy
        - Build Settingsタブを表すクラス
            - XCConfigurationList
            - XCBuildConfiguration
        - Build Phasesタブを表すクラス
            - PBXSourcesBuildPhase
            - PBXFrameworksBuildPhase
            - PBXResourcesBuildPhase
            - PBXBuildFile

ざっくり、前半と後半の２章立て。


# ファイルの構造を解読する

まず前半。`project.pbxproj` がどういう形式で表現されたファイルなのか見ていく。

## フォーマット

`objects` の要素が鬼のように長くてぱっと見はごちゃごちゃしているけど、よく見たらJSONに近い感じのフォーマットで、要素が５つだけのDictionary。

```
 {
  archiveVersion = 1;
  classes = {};
  objectVersion = 46;
  objects = {
    //// このセクションがファイル内容のほとんどを占める ///
  }
  rootObject = 9D6B60051BC4FC8A0034855E /* Project object */;
}
```

## objects 要素の中身

objectsの中身は

```
                9D6B60111BC4FC8A0034855E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D6B60101BC4FC8A0034855E /* AppDelegate.swift */; };
                9D6B60131BC4FC8A0034855E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D6B60121BC4FC8A0034855E /* ViewController.swift */; };
```

のようなレコードが延々続いている。↑だと１行に折りたたまれてるけど、内容としては

```
<id> = {
    <key> = <value>;
    <key> = <value>;
     ....
 };
...
```

となっていて第１階層とおなじフォーマットで入れ子なだけ。

`/*` `*/` で囲まれているところはコメント。

`9D6B60111BC4FC8A0034855E` とかは、あるオブジェクトを指すユニークなキー。こいつらがときどきガッツリ変わりやがるから・・・。

`isa`要素は大抵どのオブジェクトにも付いていて、そのオブジェクトのタイプを表している。（例：`isa = PBXBuildFile`)

`isa`属性ごとにセクション分けされていて、わかりやすくコメントもついてる。
生成直後のプロジェクトだと下のような構成。

```
  objects = {
/* Begin PBXBuildFile section */
 ...
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
 ...
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
 ...
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
 ...
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
 ...
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
 ...
/* End PBXNativeTarget section */

/* Begin PBXProject section */
 ...
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
 ...
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
 ...
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
 ...
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
 ...
/* End PBXVariantGroup section */
 ...
/* Begin XCBuildConfiguration section */
 ...
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
 ...
/* End XCConfigurationList section */
}
```

## rootObject

ファイルの一番末尾、第１階層の最後の要素`rootObject`が.pbxprojの構造の起点

```
 {
  archiveVersion = 1;
  classes = {};
  objectVersion = 46;
  objects = {
    ...
  }
  rootObject = 9D6B60051BC4FC8A0034855E /* Project object */;
}
```

この`9D6B60051BC4FC8A0034855E`が大量にある`objects`下の要素の１つを指している。

(↓細かい内容は流し読み可)

```
                9D6B60051BC4FC8A0034855E /* Project object */ = {
                        isa = PBXProject;
                        attributes = {
                                LastUpgradeCheck = 0700;
                                ORGANIZATIONNAME = example.com;
                                TargetAttributes = {
                                        9D6B600C1BC4FC8A0034855E = {
                                                CreatedOnToolsVersion = 7.0.1;
                                        };
                                        9D6B60201BC4FC8A0034855E = {
                                                CreatedOnToolsVersion = 7.0.1;
                                                TestTargetID = 9D6B600C1BC4FC8A0034855E;
                                        };
                                        9D6B602B1BC4FC8A0034855E = {
                                                CreatedOnToolsVersion = 7.0.1;
                                                TestTargetID = 9D6B600C1BC4FC8A0034855E;
                                        };
                                };
                        };
                        buildConfigurationList = 9D6B60081BC4FC8A0034855E /* Build configuration list for PBXProject "Example" */;
                        compatibilityVersion = "Xcode 3.2";
                        developmentRegion = English;
                        hasScannedForEncodings = 0;
                        knownRegions = (
                                en,
                                Base,
                        );
                        mainGroup = 9D6B60041BC4FC8A0034855E;
                        productRefGroup = 9D6B600E1BC4FC8A0034855E /* Products */;
                        projectDirPath = "";
                        projectRoot = "";
                        targets = (
                                9D6B600C1BC4FC8A0034855E /* Example */,
                                9D6B60201BC4FC8A0034855E /* ExampleTests */,
                                9D6B602B1BC4FC8A0034855E /* ExampleUITests */,
                        );
                };
```

このPBXProjectクラスのオブジェクトがプロジェクト設定の大元。

`ORGANIZATIONNAME = example.com;` とか `developmentRegion = English;` のようなシンプルな設定項目がありつつ、

`buildConfigurationList` や `mainGroup`、`productRefGroup`、`targets` などはさらに別のオブジェクトを指してるのがわかる。

## リンク構造

本来なんていうのかわからないけど、以降、便宜的にこういう他のオブジェクトのユニークキーを指してるのをここでは「リンク」と仮称。

たとえば

```
buildConfigurationList = 9D6B60081BC4FC8A0034855E /* Build configuration list for PBXProject "Example" */;
```

のリンクが指す先を探すと

```
/* Begin XCConfigurationList section */
                9D6B60081BC4FC8A0034855E /* Build configuration list for PBXProject "Example" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                9D6B60331BC4FC8A0034855E /* Debug */,
                                9D6B60341BC4FC8A0034855E /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
```

さらに２つのコンフィギュレーション(Debug用とRelease用)へのリンクになっているのがわかる。

なんとなくツリー構造っぽいけど、複数から非リンクしてるオブジェクトもあったりするのでツリーというわけでもない。

## リレーション関係 全体図

そんな感じで各オブジェクトのリンクを辿っていくと

![pbxproj.png](https://qiita-image-store.s3.amazonaws.com/0/27025/3689c2ad-8569-725c-2b30-74e8006386a9.png)

冒頭の図のリンク構造になってる。

## 勝手な分類

ファイル全体がだいたいどんな構造しているかがわかったので、今度は中身。

プロジェクト生成直後の.pbxprojに含まれていたクラスを、個人の主観で分類してみた。

- プロジェクトを表すクラス (rootObject)
  - PBXProject

- ファイルやディレクトリを表すクラス
  - PBXGroup
  - PBXFileReference
  - PBXVariantGroup

- ターゲットを表すクラス
  - PBXNativeTarget
  - PBXTargetDependency
  - PBXContainerItemProxy

- Build Settingsタブを表すクラス
  - XCConfigurationList
  - XCBuildConfiguration

- Build Phasesタブを表すクラス
  - PBXSourcesBuildPhase
  - PBXFrameworksBuildPhase
  - PBXResourcesBuildPhase
  - PBXBuildFile

飽くまで個人的な主観にもとづく分類。

次はこれらの中身を見ていく。

# 各クラスの中身の解読

後半。各クラスの詳細。

## PBXProject

プロジェクトを表すクラス

`project.pbxproj` のルートオブジェクト。前半の [rootObject](#rootObject)の項で見た通り、これを起点にすべてのオブジェクトがぶら下がる。

<img width="300" alt="Screen Shot 2015-10-29 at 7.01.03 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/27025/def6a8e7-8506-73f5-5f00-950d3f9cd6a8.png">

```
ORGANIZATIONNAME = example.com;
compatibilityVersion = "Xcode 3.2";
```

なんかはXcode上からも見える

しかし

```
developmentRegion = English;
```

とかはXcode上には表示もされなければ編集もできないんだろうか・・・？


## PBXGroup, PBXFireReference, PBXVariantGroup

ファイルやディレクトリを表すクラス。

### PBXGroup

Xcodeはファイルシステムとは独立に論理的なファイルのグループが作れたりするアレを表現しているクラスが`PBXGroup`。

グループに属す中身を格納する`children`要素を持っていて、その中にはまた`PBXGroup`, `PBXFireReference`, `PBXVariantGroup`とかのオブジェクトが入る。

`PBXProject`オブジェクトの中に

```
mainGroup = 9D6B60041BC4FC8A0034855E;
```

という名前でルートのグループが格納されていて

```
9D6B60041BC4FC8A0034855E = {
  isa = PBXGroup;
  children = (
    9D6B600F1BC4FC8A0034855E /* Example */,        ・・・PBXGroup
    9D6B60241BC4FC8A0034855E /* ExampleTests */,   ・・・PBXGroup
    9D6B602F1BC4FC8A0034855E /* ExampleUITests */, ・・・PBXGroup
    9D6B600E1BC4FC8A0034855E /* Products */,       ・・・PBXGroup
  );
  sourceTree = "<group>";
};
```

この中のExampleグループを更に見ると

```
9D6B600F1BC4FC8A0034855E /* Example */ = {
  isa = PBXGroup;
  children = (
    9D6B60101BC4FC8A0034855E /* AppDelegate.swift */,       ・・・PBXFireReference
    9D6B60121BC4FC8A0034855E /* ViewController.swift */,    ・・・PBXFireReference
    9D6B60141BC4FC8A0034855E /* Main.storyboard */,         ・・・PBXFireReference
    9D6B60171BC4FC8A0034855E /* Assets.xcassets */,         ・・・PBXFireReference
    9D6B60191BC4FC8A0034855E /* LaunchScreen.storyboard */, ・・・PBXVariantGroup
    9D6B601C1BC4FC8A0034855E /* Info.plist */,              ・・・PBXFireReference
  );
  path = Example;
  sourceTree = "<group>";
};
```

こんな感じで

![Screen Shot 2015-10-16 at 12.06.05 AM.png](https://qiita-image-store.s3.amazonaws.com/0/27025/ad7cf215-e911-a607-4cfb-c36416cd71ae.png)


Xcode上から見たファイルリストを表してるのが見て取れる。

論理グループとファイルシステムは綺麗に対応付けるのがベストプラクティスということになってると思うので、
常に

```
path = ディレクトリ名;
sourceTree = "<group>";
```

になるように気をつければ良いはず。`path = "xxx/yyy/zzz/ディレクトリ名"`とかになってると変な取り込み方をしている可能性大。

### PBXFireReference

↑でも出てきているように、
ソースコードはもちろん、frameworkファイルやプロダクトファイル(`***.a`なアレ)などファイルシステム上のすべてのファイルは表現しているクラス。

```
9D6B60101BC4FC8A0034855E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
```

敢えて改行はせずに、1ファイル1行になるようにしてくれている。

これも常に

```
path = ファイル名; sourceTree = "<group>";
```

になるはず。ただし次に出てくる`PBXVariantGroup`絡みのファイルだけは別。

### PBXVariantGroup

`PBXVariantGroup`は、Localizationされているファイルを表現するクラスで、実際は日本語版・英語版のファイルあるのに、Xcode上で見ると1つの`.strings`ファイル、みたいなアレ。

```
9D6B60141BC4FC8A0034855E /* Main.storyboard */ = {
  isa = PBXVariantGroup;
  children = (
    9D6B60151BC4FC8A0034855E /* Base */, ・・・PBXFileReference
  );
  name = Main.storyboard;
  sourceTree = "<group>";
};
```

LocalizationでBaseを持っていて、対応するファイルは

```
9D6B60151BC4FC8A0034855E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
```

ローカライズされていると`言語.lproj/`下に置かれて、`path = Base.lproj/Main.storyboard;`となるらしい。

こうなっているせいで、一度間違ってローカライズを解除してしまったり、ローカライズされたファイルを移動させてしまうと元に戻すのに死ぬ思いをさせられる。
Xcode上から復旧するの無理なんじゃないだろうかアレ。

解読できた今なら、.pbxprojファイルを直接編集してスパっと復旧できること間違いなし。


## PBXNativeTarget, PBXTargetDependency, PBXContainerItemProxy

ターゲットや、ターゲット間の依存関係を定義するクラス

### PBXNativeTarget

ターゲットを表すクラス。

PBXProjectオブジェクトに格納されてる。

```
targets = (
  9D6B600C1BC4FC8A0034855E /* Example */,
  9D6B60201BC4FC8A0034855E /* ExampleTests */,
  9D6B602B1BC4FC8A0034855E /* ExampleUITests */,
);
```

リンク先は

```
9D6B600C1BC4FC8A0034855E /* Example */ = {
  isa = PBXNativeTarget;
  buildConfigurationList = 9D6B60351BC4FC8A0034855E /* Build configuration list for PBXNativeTarget "Example" */;
  buildPhases = (
    9D6B60091BC4FC8A0034855E /* Sources */,    ・・・ 
    9D6B600A1BC4FC8A0034855E /* Frameworks */,
    9D6B600B1BC4FC8A0034855E /* Resources */,
  );
  buildRules = (
  );
  dependencies = (
  );
  name = Example;
  productName = Example;
  productReference = 9D6B600D1BC4FC8A0034855E /* Example.app */;
  productType = "com.apple.product-type.application";
};
```

PBXProjectと同じく`buildConfigurationList`として`XCConfigurationList`オブジェクトを持っている。
(Build Settigsはプロジェクト設定、ターゲット設定両方ある)

一方で、`buildPhases` はPBXProjectにはなかった項目。
(Build Phasesはターゲットにだけあってプロジェクトにはない)

### PBXTargetDependency

<img width="300" alt="Screen Shot 2015-10-29 at 6.50.15 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/27025/43f1826b-2211-47e4-e49e-ada94be44de9.png">

おそらく、Build PhaseのTarget Dependenciesの元情報

↑の例にした`Example`はメインのターゲットなので`dependencies`が空。

単体テストターゲットやUIテストターゲットは、メインのターゲットに依存する設定になってる。

```
9D6B60201BC4FC8A0034855E /* ExampleTests */ = {
  isa = PBXNativeTarget;
  buildConfigurationList = 9D6B60381BC4FC8A0034855E /* Build configuration list for PBXNativeTarget "ExampleTests" */;
  buildPhases = (
    9D6B601D1BC4FC8A0034855E /* Sources */,
    9D6B601E1BC4FC8A0034855E /* Frameworks */,
    9D6B601F1BC4FC8A0034855E /* Resources */,
  );
  buildRules = (
  );
  dependencies = (
    9D6B60231BC4FC8A0034855E /* PBXTargetDependency */,
  );
  name = ExampleTests;
  productName = ExampleTests;
  productReference = 9D6B60211BC4FC8A0034855E /* ExampleTests.xctest */;
  productType = "com.apple.product-type.bundle.unit-test";
};
```

dependenciesのリンク先の`PBXTargetDependency`が依存の情報を保持している。

```
9D6B60231BC4FC8A0034855E /* PBXTargetDependency */ = {
  isa = PBXTargetDependency;
  target = 9D6B600C1BC4FC8A0034855E /* Example */;
  targetProxy = 9D6B60221BC4FC8A0034855E /* PBXContainerItemProxy */;
};
```

よくわからないのが、`target = 9D6B600C1BC4FC8A0034855E /* Example */;`だけで依存先の情報は十分な気がするのに、
謎の`targetProxy = 9D6B60221BC4FC8A0034855E /* PBXContainerItemProxy */;`という項目も存在している。次項。

### PBXContainerItemProxy

謎。↑の`PBXTargetDependency`から`targetProxy`として参照されてるけど、
存在意義がわからない。

```
9D6B60221BC4FC8A0034855E /* PBXContainerItemProxy */ = {
  isa = PBXContainerItemProxy;
  containerPortal = 9D6B60051BC4FC8A0034855E /* Project object */; ・・・ PBXProjext:rootObject
  proxyType = 1;
  remoteGlobalIDString = 9D6B600C1BC4FC8A0034855E;                 ・・・ PBXNativeTarget:Example
  remoteInfo = Example;
};
```

これがなくても、依存の情報は揃っている気がする・・・。

## XCConfigurationList, XCBuildConfiguration

<img width="300" alt="Screen Shot 2015-10-29 at 6.44.46 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/27025/61974427-b802-3a7b-bde6-95d5496a9ffa.png">

Build Settingsの項目を表すクラス。

PBXProject,　PBXNativeTargetそれぞれが持っていて、合計4つ(プロジェクト, Exampleターゲット, ExampleTestsターゲット, ExampleUITestsターゲット)の`XCConfigurationList`がある。

さらにデフォルトでDebugとReleaseの2つのコンフィギュレーションが用意されるので、合計8つ(4 x 2 = 8)の`XCBuildConfiguration`がある。

同じような記述が何回も繰り返し出てくることになって、コンフリクトしたときとかによく混乱させてくれる。

### XCConfigurationList

プロジェクトの分。

```
                9D6B60081BC4FC8A0034855E /* Build configuration list for PBXProject "Example" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                9D6B60331BC4FC8A0034855E /* Debug */,
                                9D6B60341BC4FC8A0034855E /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
```

`Example`ターゲットの分。

```
                9D6B60351BC4FC8A0034855E /* Build configuration list for PBXNativeTarget "Example" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                9D6B60361BC4FC8A0034855E /* Debug */,
                                9D6B60371BC4FC8A0034855E /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                };
```

プロジェクトのでもターゲットのでもフォーマットは同じ。

Debug/Releaseそれぞれの`XCBuildConfiguration`を格納している。

### XCBuildConfiguration

Build Settings欄で見慣れた設定値たち。

```
                9D6B60331BC4FC8A0034855E /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_MODULES = YES;
                                SWIFT_OPTIMIZATION_LEVEL = "-Onone";
                                TARGETED_DEVICE_FAMILY = "1,2";
                                ...省略...
                        };
                        name = Debug;
                };
```

同じ名前の設定項目が何個もあってどれを変えるのが正しいのかわからなかったのは過去の話。

これからは、必要に応じてターゲットオブジェクトから辿りつつ、目的の`XCBuildConfiguration`オブジェクトを探せばOK。

## PBXSourcesBuildPhase, PBXFrameworksBuildPhase, PBXResourcesBuildPhase と PBXBuildFile

<img width="300" alt="Screen Shot 2015-10-29 at 6.52.29 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/27025/02e1ea7b-2ae1-afd8-74fb-6a0e93633235.png">

Build Phasesのうち、Target Dependencies以外の内容を表すクラス

プロジェクト生成直後だとこの3つだけしかないけど、CocoaPodsとか使うと`PBXScriptBuildPhase`が増えたり、他にもまだありそう。

8つもあった`XCBuildConfiguration`と違って、

- プロジェクトはBuild Phasesの設定は持たない
- Debug/Releaseとかのコンフィギュレーションにも依らない

ので、ターゲットの数＝3つずつオブジェクトが存在する。だいぶ少ない気分になれる。

### PBXSourcesBuildPhase

ビルドに含めるソース。

こんな感じで各ターゲット分で3つ。

```
/* Begin PBXSourcesBuildPhase section */
		9D6B60091BC4FC8A0034855E /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				9D6B60131BC4FC8A0034855E /* ViewController.swift in Sources */, ・・・PBXBuildFile
				9D6B60111BC4FC8A0034855E /* AppDelegate.swift in Sources */,    ・・・PBXBuildFile
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		9D6B601D1BC4FC8A0034855E /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				9D6B60261BC4FC8A0034855E /* ExampleTests.swift in Sources */,   ・・・PBXBuildFile
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		9D6B60281BC4FC8A0034855E /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				9D6B60311BC4FC8A0034855E /* ExampleUITests.swift in Sources */,  ・・・PBXBuildFile
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */
```

Testsターゲット用のソースをまちがってメインターゲットに取り込んでしまう、などのミスがないように気をつける。

他のPhaseでも同様。

### PBXFrameworksBuildPhase

ビルドに含めるframework。

プロジェクト生成当初はどのターゲットもframeworkは空だった。

```
		9D6B600A1BC4FC8A0034855E /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
```

未確認だけど、なんかXcode8あたりからframeworkをわざわざ指定しなくても自動で取り込んでくれるようになったとかそんなニュースがあったような・・・？

### PBXResourcesBuildPhase

ビルドする際に取り込むリソース。アプリのバイナリにバンドルされる（はず）

```
9D6B600B1BC4FC8A0034855E /* Resources */ = {
  isa = PBXResourcesBuildPhase;
  buildActionMask = 2147483647;
  files = (
    9D6B601B1BC4FC8A0034855E /* LaunchScreen.storyboard in Resources */,  ・・・PBXBuildFile
    9D6B60181BC4FC8A0034855E /* Assets.xcassets in Resources */,  ・・・PBXBuildFile
    9D6B60161BC4FC8A0034855E /* Main.storyboard in Resources */,
  );
  runOnlyForDeploymentPostprocessing = 0;
};
```

注意事項として、`Info.plist`はリソースとして取り込む必要がない。

一度`Info.plist`をXcodeから論理削除してもう一度取り込み直すときに、ターゲットに含めるチェックボックスをオンにしたりしてると意図せずここに含まれてしまうことがよくある気がする。

### PBXBuildFile

○○BuildPhaseはこのクラスのオブジェクトを経由して、ビルドするソースやリソースのPBXFileReferenceやPBXVariantGroupを参照している。

なんで中間が必要なのかはわからないけど。

```
                9D6B60111BC4FC8A0034855E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D6B60101BC4FC8A0034855E /* AppDelegate.swift */; };  ・・・ PBXFileReference
9D6B60161BC4FC8A0034855E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D6B60141BC4FC8A0034855E /* Main.storyboard */; };  ・・・PBXVariantGroup
```


# おわり

以上！

![pbxproj.png](https://qiita-image-store.s3.amazonaws.com/0/27025/3689c2ad-8569-725c-2b30-74e8006386a9.png)

最後にもう一度全体図を見ると・・・なんとなくイメージが伝わるようになっていると嬉しいです。

長文になりましたが、ここまで読んで頂いた奇特な方、どうもありがとうございます。

これで`git diff`したときもソースレビューのときも、.pbxprojファイルを読み飛ばさずにしっかりチェックできるはず。

プロジェクト設定がなんかカオスな感じにおかしくなってるプロジェクトを引き継いだって怖くない。