個人開発でXcodeプロジェクトの新規作成時にやること
はじめに
2025年の1月現在で、iOSアプリの個人開発において自分がプロジェクトで設定することを書いてみます。Xcode 16.2です。
下記の記事に触発されました。
前提として今の環境で自分ならこうするというものを書いておきます。仕事でどうやるかはチームとかで決めれば良いと思います。
.editorconfig
Xcode 16から.editorconfig
ファイルを置くことで、プロジェクトごとにXcode設定を変更できるようになっています。
# editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
-
[*]
- 全てのファイル拡張子に適用
- もし設定ファイルやドキュメントで別ルールを除外したい場合が出たら拡張子指定
- 例:
[.md]
- 例:
- もし設定ファイルやドキュメントで別ルールを除外したい場合が出たら拡張子指定
- 全てのファイル拡張子に適用
-
indent_size
は2- SwiftUIは特にインデントして右側にコードが行ってしまう
- editorconfigが出る前は4を変えてしまうとプロジェクトごとに設定を変更する必要があった
- 仕事用は4で個人用は2にするのが面倒だったが、個人用を2にできる
- 徐々に仕事用も2に説得していける
- 仕事用は4で個人用は2にするのが面倒だったが、個人用を2にできる
- editorconfigが出る前は4を変えてしまうとプロジェクトごとに設定を変更する必要があった
- TypeScriptやら他言語は大抵2なのでそれにあわせたい
- SwiftUIは特にインデントして右側にコードが行ってしまう
-
trim_trailing_whitespace
はtrue- 行末の空白を自動削除
-
end_of_line
はLF- macOSを使うので改行コードはLFでいいと思う
- Unix系もLFなのでGitHub Actionsのファイルを考えてもLFでいいと思う
-
insert_final_newline
はtrue- ファイル末尾が改行されてなければ改行
trim_trailing_whitespace
をプロジェクトで共有できるのは個人開発というか仕事で役に立ちます。いままでXcodeにもありましたが、それをいちいち説明するが面倒でした。
.editorconfigをプロジェクトに追加
.editorconfigはルートに置けばいいですが、さらにXcodeのプロジェクト内で開けるようにします。
Xcodeでコード書くときに設定をプロジェクトに追加しないのはいちいち別のエディタで開く必要がありかったるいです。たまに仕事でyamlファイルとか扱いますが、それも同じ。もちろんビルド対象になってないことを自分の目で確認することが必要です。
不要なSupported Destinationを消しMac(Designd By iPhone)は残す
iPhoneアプリだけでいいならiPad/VisionOSのサポートを消します。
デフォルトでMac(Desgined By iPhone/iPad)があると思いますがこれは残す。
iPhoneアプリをMacアプリとして起動しデバッグするメリットは、書いたコードの実行がiOSシミュレータを起動するよりも早いからです。つまり、簡単なことを確認したいだけのときいちいちiOSのシミュレータを起動してられないことがあるからです。
もちろん見た目はmacアプリなので表面的なデザインの確認はできませんし、iOSシミュレータにしかない機能は使えません。iOSデバイスにしかない機能ももちろん確認できません。さらに注意点として、macアプリの実機で動作させるので実機実行の証明書関連をクリアにする必要はあります。
Local Packageにコードを書けるようにする
構成として最小限にするため、アプリのホスト側はAppに準拠する構造体と、必要であればAppDelegateのみにします。
- アプリのホスト(
App
やAppDelegate
やSceneDelegate
)のみ- Local PackageとしてSwift Packageに全部書く
機能はModulesというLocal Packageにコードを書く。アプリのホスト側はModulesを呼び出すだけ。
なぜこうするかというと、大抵の機能やらはアプリの本体側に書く必要がないからです。シンプルな構成にしたいのと、Local Pacakgeに書いておいたらそれをあとは自由に組み替えればいいからです。あと外部のライブラリをPacakge.swiftでコードとして書きたいからです(XcodeのPackage DependenciesをGUIから設定したくない)。
また、コード自体がLocal package側にあるわけだからテストコードもそちらにかけます。そしてswift test
が実行できるテストを作れる状態にすることもメリットです。swift test
でテストできるのであればiOSシミュレータを起動する必要がなく、iOSシミュレータの起動ができないなどのトラブルも避けることができるし、そもそもテストの実行時間が短縮されますし、iOSシミュレータに依存したテストにならないので安定します。
ただ注意点もあるので後述しています。
XcodeでLocal Pacakgeを使う方法
やり方は2つあります。
- XcodeにLocal PackageをAddする
- さらに細かくAdd手順は2つ
- Project側をXcodeで開いて、Local PacakgeもXcodeで開いてDrag And Drop
- 左下の
+
ボタンからAdd FilesでPacakageのフォルダを指定
- さらに細かくAdd手順は2つ
- XcodeのPacakge DependencyとしてGUIからLocal Pacakgeを追加する
後者の2がAppleのドキュメントでよく説明されています。なので後者でもいいけど、Local PackageのテストコードをSchemeに設定する方法が私にはわからないので前者の方法を使っています。
もし前者の1のやり方がダメとなっても、どちらにせよ、後者のやり方にするのも簡単なので気にせず前者のやり方をしています。
Local Pacakgeを使う際に残りやること
あとはどうでもいいこととして、少しやることはあります。XcodeのGUIで設定します。
- Modules側のテストをxctestplanに登録
- Package側をビルドできるようにSchemeに登録
swiftLanguageModes(Swift Language Version)の指定
swiftLanguageModesを指定するのはここまでの設定をしてるなら2箇所あるはずです。
- Xcode自体のホスト側の指定
- Local Package側の指定
Xcode 16を使っている時点でツールバージョンはSwift 6であり、Swift 6でビルドできるはずです。その上でswiftLanguageModesを6にするか5.xにするかという設定をします。
swiftLanguageModesを6にすると、Swift 5時のUpcomming Feature FlagをまとめてYESにできる、ぐらいの認識でいいと思います(間違っていたら指摘をお願いします)。
swiftLanguageModesのデフォルトである5の場合を確認
Projectの設定からUpcomming Featureで検索するとデフォルトでNoになっているはずです。
これはあくまで確認するだけです。この設定で個別に変更してもいいですが、swiftLanguageModesで6に指定します。
こうするとUpcomming Featureで関連するものたちがYesになるはずです。
初手なんで対してコードが存在しないはずで、全部Yesでいいと思いますが、どうしても警告が出て解決できない場合に個別にNoにしたりすればいいと思います。
Local Package側もPackage.swiftにswiftLanguageModesとしてv6を指定してみます。
.target(
name: "Modules"
swiftSettings: [
.swiftLanguageMode(.v6)
]
),
あんまりよくわからないswiftLanguageModesとは何かについては別の記事で書いてます。
vscodeやcursorで動かす
Sweetpad
拡張でSweetpadをインストールすることでxcodebuildコマンドを呼び出してくれたり、他のツールと組み合わせてくれます。
初手としてコードや設定が少ないうちにビルド成功するのをみたほうがいいです。初手でSweetpadのビルド失敗すると言うことは、なんかしら拡張の設定やらmacOS自体の何かしらが失敗しているはずで、状況の切り分けが明確になります。
あまり詳しく調査できていませんが、Objective-Cを含むプロジェクトだとビルド失敗すると思います。
docs/を作ってそこにmdドキュメントを書く
iOSアプリに限らず個人開発の場合、プロジェクト内にドキュメント用のフォルダをつくってドキュメンをためます。
inkdropとかObisidianに書いても分散してしまうので、もうプロジェクトのことはプロジェクト内に書く。
Localization
デフォルトだとEnglishです。
まず日本語版しか作らないならJapaneseを作成してEnglish消す。
記憶がたしかではないですが、Englishのまま日本語をハードコードすると、App Storeのアプリ詳細で英語にしか対応してないように見えるんじゃないかな(実際は起動すると日本語)。違いましたかね?
あとでやればいいこと
DerivedDataのパスをプロジェクト配下にする
プロジェクト固有の話じゃないんですが、XcodeのGUIから.build/DerivedData
を指定すると、プロジェクト配下からアクセスできる場所にDerivedDataを置けます。簡単に消したいので近くにあればいい。
Explict modulesを有効にするのは測定してからの方がいい
Xcode 16からExplict modulesを有効にすることができますが、Xcode 16.1で試したところ、クリーンビルド後のPlanningのフェーズが遅いです。もしかしたらめちゃくちゃ小さいProjectだと違いがないどころか遅くなっていて、大きなProjectならビルドが速く終わる損益分岐点があるかもしれないです。とにかく何も考えずにやらない方がいい。絶対に測って確認すべきです。
Xcode 15か14あたりからAssistantを有効化にするとビルド時のステップを視覚化できます。
他のブログ記事でも速くなってないとか書かれています。
どうでもいいこと
話が脱線しますが、細かくて他の記事にするのもどうかという細かいことを書いておきます。
キーボードショートカットキーとキーマクロ
.editorconfigでインデントを2にしたのをファイルごとに指定する方法について書いておきます。
Xcodeのエディタ設定に従ってインデントを変更してくれるショートカットがあり、選択してそれを実行することでインデントを変更することができます。
私はインデントの一括変更のショートカットキーはKeychronのキーボードマクロに登録していて、このショートカットと、cmd a
のファイル全指定をM3キーに割当ててます。
脱線しまくりですが、テスト実行も「直近のテストを実行する」というショートカットキーが存在するのでそれも同じようにM5キーに割り当て。「カーソル位置のテストのみを実行」をM4キーに割当ててます。
swift testコマンド
macOSからswift test
コマンドでLocal Packageのテストを実行するとき、SDKとしてはmacOS SDKを使ってmacOS用のバイナリを作っているようで、Package.swiftのplatformsにiOSを指定してもそれは適用されません。
そのため、macOSでリリースしたいわけじゃなくても、そのPackageのplatformsにmacOSを指定すると良いと思ってます。
let package = Package(
name: "Modules",
platforms: [
.iOS("18.0.0"),
.macOS(.v12) // 最終的にmacOSでリリースしたいわけじゃないが書いておく
],
考え
なんでこうなるかというと、swift build
は純粋にswiftの機能だからだと思います。xcodebuild test
はiOS用のコードをクロスコンパイルしていたり、シミュレータを起動してテストを行えるが、swift build
はそれ自身を純粋に実行しようとするプラットフォームで動作するバイナリを作ってテストする機能だからだと思います。
めちゃくちゃ脱線しますが、Package.swiftをSwift 6とSwift 5で分けているOSSがあるように、テスト用のPackage.swiftがないとテスト実行できないなら、CI上でそれを作るというアイデアがあるかもしれないですね。
おわりに
基本的に人がどうやろうと自由だと思いますが、たいてい複雑なことをしようとしないのがベストな気がします。ただ無駄なものは削除したほうがわかりやすいし、デフォルト動作が暗黙的な気がするなら明示したい。個人開発でも過去の自分に属人化してしまうのでdocsつくったほうがいい。
あと標準で足りないことをオプトインで無闇に有効にするなら効果を測定しないと結局個人開発でスピードを落としてたら自己満足しかない。そういう意味では、 swiftLanguageModesも5でいいし、モジュール分割も何もやらないのが一番かもしれないですね。
関連
Schemeをわざわざ分けて使わないでくださいという話も別に書いてます。
Discussion