Your First iOS & SwiftUI App: Polishing the App

Mar 1 2022 · Swift 5.5, iOS 15, Xcode 13

Part 4: A Second Screen

39. Connect the Leaderboard

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 38. Challenge: Leaderboard Data Model Next episode: 40. App Icon & Display Name
Transcript: 39. Connect the Leaderboard

Now that we have the data model in place, it’s time to hook it up to the leaderboard view.

Rather than just displaying a single hardcoded row, we will now display one row for each leaderboard entry.

To do this, we will make use of our old friend ForEach, which you may recall helped us create a bunch of Ring Views in the background.

We’ll also use a new SwiftUI View called ScrollView, which will make the view scrollable if there are more entries than can fit on one screen. Let’s try this out.

Add to LeaderboardView:

@Binding var game: Game

Update LeaderboardView_Previews:

struct LeaderboardView_Previews: PreviewProvider {
  static private var leaderboardIsShowing = Binding.constant(true)
  static private var game = Binding.constant(Game())

  static var previews: some View {
    LeaderboardView(leaderboardIsShowing: leaderboardIsShowing, game: game)
      .environment(\.horizontalSizeClass, .compact)
    LeaderboardView(leaderboardIsShowing: leaderboardIsShowing, game: game)
      .previewLayout(.fixed(width: 568, height: 320))
    LeaderboardView(leaderboardIsShowing: leaderboardIsShowing, game: game)
      .preferredColorScheme(.dark)
      .environment(\.horizontalSizeClass, .compact)
    LeaderboardView(leaderboardIsShowing: leaderboardIsShowing, game: game)
      .previewLayout(.fixed(width: 568, height: 320))
      .preferredColorScheme(.dark)
  }
}

And in BackgroundView:

LeaderboardView(leaderboardIsShowing: $leaderboardIsShowing, game: $game)

In LeaderboardView, replace RowView with:

VStack(spacing: 10) {
  ForEach(game.leaderboardEntries.indices) { i in
    let leaderboardEntry = game.leaderboardEntries[i]
    RowView(index: i + 1, score: leaderboardEntry.points, date: leaderboardEntry.date)
  }
}

We see no test data. To fix this, add to Game.swift:

init(loadTestData: Bool = false) {
  if loadTestData {
    leaderboardEntries.append(LeaderboardEntry(points: 100, date: Date()))
    leaderboardEntries.append(LeaderboardEntry(points: 80, date: Date()))
    leaderboardEntries.append(LeaderboardEntry(points: 60, date: Date()))
    leaderboardEntries.append(LeaderboardEntry(points: 40, date: Date()))
    leaderboardEntries.append(LeaderboardEntry(points: 20, date: Date()))
  }
}

Update Leaderboard_Previews:

static private var game = Binding.constant(Game(loadTestData: true))

Wrap the VStack in a ScrollView:

ScrollView {
  VStack(spacing: 10) {
    ForEach(game.leaderboardEntries.indices) { i in
      let leaderboardEntry = game.leaderboardEntries[i]
      RowView(index: i + 1, score: leaderboardEntry.points, date: leaderboardEntry.date)
    }
  }
}

Build & run. Add a bunch of entries, and show it worknig.

Show how the X button now appears on top of the view, since not enough padding. To fix, add to bottom of HeaderView:

.padding(.top)