Skip to content

[Foundation/Feature] Pokémon Evolution Dex — scaffold, domain models & parallel family loading#2

Open
SongMY01 wants to merge 11 commits into
mainfrom
swift-testing/martin/asynchronous-testing-patterns
Open

[Foundation/Feature] Pokémon Evolution Dex — scaffold, domain models & parallel family loading#2
SongMY01 wants to merge 11 commits into
mainfrom
swift-testing/martin/asynchronous-testing-patterns

Conversation

@SongMY01
Copy link
Copy Markdown

@SongMY01 SongMY01 commented Jun 6, 2026

What problem does this solve?

Builds a SwiftUI Pokédex on the PokeAPI for the Swift Concurrency Lab.
Shows how async/await, TaskGroup, and @MainActor behave in a real app by loading 50 evolution families + every stage's detail (~150 requests) in parallel — sequentially ~45s, in parallel ~0.6s.


Approach

ContentView ──→ PokemonViewModel ──→ «protocol» PokemonService
   (View)         (@MainActor)              ▲ implements
                                     PokemonServiceImpl ──→ PokeAPI
  • ModelsPokemon, PokemonFamily (one evolution chain per card)
  • Serviceprotocol PokemonService: Sendable (async/throws). PokemonServiceImpl decodes JSON via private DTOs — external shape never leaks past the boundary. ViewModel depends only on the protocol → mock injectable for Testing Lab later.
  • ViewModel@MainActor, orchestrates concurrency with nested TaskGroups
  • View — card UI tinted by primary type, per-type colors, Pretendard variable font

Concurrency Core

Outer TaskGroup ─ 50 families concurrently
   └ Each family: fetchEvolutionChain (must run first — data dependency)
        └ Inner TaskGroup ─ that family's stages concurrently (fetchDetail × N)
  • Across families: concurrent · within a family: chain-then-details (dependency)
  • Ordering: results arrive scrambled → collected into [id: Pokemon], then speciesIDs.compactMap { byID[$0] } restores evolution order
  • Safety: @MainActor keeps @Published updates on main; Sendable lets the service cross task boundaries; loadFamily is static + arg-passed so it never captures the MainActor self

Diagram

Diagram

Review Focus

  • Is the nested TaskGroup shape right, or would a flatter structure read more clearly?
  • Error handling: any task failure currently resets families = [] — should partial results survive instead?
  • Are the Pokemon / PokemonFamily field shapes right for the UI?
  • Is the PokemonService boundary (async / throws / Sendable) the right contract?

Out of Scope / Follow-up

  • Swift Testing suite (mock PokemonService, success/failure/timeout/cancellation)

SongMY01 and others added 11 commits May 23, 2026 00:48
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Pokemon: id, name, imageURL, types; conforms to Identifiable
- PokemonFamily: one evolution chain holding id and stages

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- fetchEvolutionChain(id:): returns ids in evolution order
- fetchDetail(id:): detail including image and types
- Conforms to Sendable

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Calls PokeAPI and decodes responses
- Flattens the evolution-chain tree into evolution order
- Separate DTOs for decoding responses

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fetches families and stages concurrently via outer/inner TaskGroups
- Restores arrival order using the chain order (speciesIDs)
- Ensures concurrency safety with @mainactor and Sendable

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Bundles PretendardVariable.ttf and registers it at launch (CTFontManager)
- Adds Font/UIFont helpers with variable weight and Dynamic Type
- Sets the navigation bar title font

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ContentView shows each family as a card; horizontal scroll for 4+ stages
- Adds PokemonTypeStyle mapping 18 official type colors
- Type-color gradient cards, type badges, Pokedex numbers, light theme

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- pokemon/README.md: overview, architecture, and concurrency implementation

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Automatic code signing / development team settings
- Ignore .DS_Store and Xcode user data

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant