167
130

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

.xcodeproj/project.pbxproj を解読する

Last updated at Posted at 2015-10-29

(2018/01/28 追記)

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

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

(2019/10/05 追記)

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

(追記おわり)

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

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

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

pbxproj.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

(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

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

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

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

フォーマット

objects の要素が鬼のように長くてぱっと見はごちゃごちゃしているけど、よく見たらJSONに近い感じのフォーマットで、要素が5つだけの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 */; };

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

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

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

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

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

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

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

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

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

                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; のようなシンプルな設定項目がありつつ、

buildConfigurationListmainGroupproductRefGrouptargets などはさらに別のオブジェクトを指してるのがわかる。

リンク構造

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

たとえば

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;
                };

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

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

リレーション関係 全体図

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

pbxproj.png

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

勝手な分類

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

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

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

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

    • PBXGroup
    • PBXFileReference
    • PBXVariantGroup
  • ターゲットを表すクラス

    • PBXNativeTarget
    • PBXTargetDependency
    • PBXContainerItemProxy
  • Build Settingsタブを表すクラス

    • XCConfigurationList
    • XCBuildConfiguration
  • Build Phasesタブを表すクラス

    • PBXSourcesBuildPhase
    • PBXFrameworksBuildPhase
    • PBXResourcesBuildPhase
    • PBXBuildFile

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

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

各クラスの中身の解読

後半。各クラスの詳細。

PBXProject

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

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

Screen Shot 2015-10-29 at 7.01.03 PM.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

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

Screen Shot 2015-10-29 at 6.50.15 PM.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

Screen Shot 2015-10-29 at 6.44.46 PM.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

Screen Shot 2015-10-29 at 6.52.29 PM.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

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

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

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

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

167
130
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
167
130

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?