0Pricing
Swift Academy · レッスン

DIフレームワークを使わずにレイヤーを接続する

Composition Rootパターンを使い、アプリのエントリーポイントでオブジェクトを組み立てます。

「DIフレームワークを使わずにレイヤーを接続する」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全4レッスンが含まれています。

Composition Root

Composition Rootは、すべてのオブジェクトを生成して接続する1か所の場所です。SwiftUIアプリでは、通常 @main がその役割を担います。

@main
struct MyApp: App {
  // All wiring happens here
  private let container = AppContainer()
  var body: some Scene {
    WindowGroup { container.makeRootView() }
  }
}

AppContainerパターン

AppContainer のstructやclassでオブジェクトグラフを構築し、複雑な接続処理をApp structから隠します。

final class AppContainer {
  let db = SQLiteDatabase()
  lazy var userRepo: UserRepository = RemoteUserRepository(db: db)
  lazy var fetchUser = FetchUserUseCase(repo: userRepo)
  lazy var profileVM = ProfileViewModel(useCase: fetchUser)
  func makeRootView() -> some View { ProfileView(viewModel: profileVM) }
}

順序を制御するlazyプロパティ

lazy プロパティを使用すると、手動で順序を指定しなくても、依存関係を正しい順序で構築できます。

final class Container {
  lazy var network: NetworkClient = URLSessionClient()
  lazy var api: APIService = APIService(client: network)  // created after network
  lazy var repo: ItemRepository = RemoteItemRepository(api: api)
}

ファクトリーメソッド

コンテナにファクトリーメソッドを追加し、画面ごとの依存関係を持つビュー用オブジェクトを生成します。

extension AppContainer {
  func makeOrderFlow() -> OrderFlowView {
    let repo = RemoteOrderRepository(api: api)
    let useCase = PlaceOrderUseCase(repo: repo)
    let vm = OrderViewModel(useCase: useCase)
    return OrderFlowView(viewModel: vm)
  }
}

注入に使うEnvironment Values

SwiftUIでは、カスタム EnvironmentKey を使用すると、プロパティを何層も受け渡すことなく、ビュー階層の深い場所に依存関係を注入できます。

private struct FetchUserKey: EnvironmentKey {
  static let defaultValue: FetchingUser = FetchUserUseCase(repo: NullUserRepo())
}
extension EnvironmentValues {
  var fetchUser: FetchingUser {
    get { self[FetchUserKey.self] } set { self[FetchUserKey.self] = newValue }
  }
}

Environment Keyの使用

.environment(\.fetchUser, container.fetchUser) で注入し、ビュー内で @Environment(\.fetchUser) を使って読み取ります。

ContentView()
  .environment(\.fetchUser, container.fetchUser)

// In a deep view:
@Environment(\.fetchUser) private var fetchUser

スコープ付きコンテナ

機能ごとのスコープに子コンテナを作成します。共有依存関係を引き継ぎながら、機能固有の依存関係を管理できます。

final class CheckoutContainer {
  let cart: CartRepository
  let payment: PaymentService
  lazy var placeOrder = PlaceOrderUseCase(cart: cart, payment: payment)
  init(parent: AppContainer) {
    cart = parent.cartRepo
    payment = parent.paymentService
  }
}

Composition Rootのテスト

コンテナのファクトリーメソッドをテストし、返されるオブジェクトが正しい型と設定になっていることを検証します。

func testContainerBuildsProfileView() {
  let container = AppContainer(db: InMemoryDatabase())
  let view = container.makeRootView()
  XCTAssertTrue(type(of: view) == ProfileView.self)
}

循環依存の回避

AがBに依存し、BもAに依存している場合は、メディエーターを導入するか責務を再構成して、循環を解消します。

// Circular:
// UserService → NotificationService → UserService
// Fix: UserService → NotificationInput (protocol) ← NotificationService

DIフレームワークを使うタイミング

中規模のアプリまでは、手動での接続が十分に対応できます。コンテナの保守が難しいほど大きくなった場合に限り、フレームワーク(Needle、Swinject)の導入を検討します。

// Manual: fine for <20 top-level dependencies
// Framework: helps with large teams, 50+ services, code-generation for factories

まとめの例

小規模なアプリでの接続全体の例です。コンテナがすべての依存関係を構築し、ファクトリーがルートビューを生成します。

final class AppContainer {
  private let db = CoreDataStack.shared
  lazy var userRepo: UserRepository = LocalUserRepository(db: db)
  lazy var fetchUser = FetchUserUseCase(repo: userRepo)
  func makeContentView() -> ContentView {
    ContentView(viewModel: ProfileViewModel(useCase: fetchUser))
  }
}

確認問題

SwiftアプリにおけるComposition Rootとは何ですか。

学習内容のまとめ

アプリはComposition Root(通常は @main)で接続します。lazy プロパティを持つ AppContainer を使用して、正しい構築順序を保ちます。画面ごとのオブジェクトグラフにはファクトリーメソッドを追加します。カスタム EnvironmentKey を使って、深い階層の依存関係を注入します。循環依存はメディエータープロトコルで解消します。

よくある質問

「DIフレームワークを使わずにレイヤーを接続する」レッスンは無料ですか?

はい。「DIフレームワークを使わずにレイヤーを接続する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全4レッスンが含まれています。

「DIフレームワークを使わずにレイヤーを接続する」で何を学びますか?

Composition Rootパターンを使い、アプリのエントリーポイントでオブジェクトを組み立てます。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Swift Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「DIフレームワークを使わずにレイヤーを接続する」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このSwift Academyレッスンでコードを書いて実行できますか?

はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. レイヤー:ドメイン、データ、プレゼンテーション
  2. ユースケースとリポジトリパターン
  3. プロトコル抽象化による依存性逆転
  4. DIフレームワークを使わずにレイヤーを接続する
← Swift Academyに戻る