【Xcode/SwiftUI】Building a Pokemon List App with UserDefaults in SwiftUI

If you’re a fan of Pokemon, then you probably want to keep track of all the Pokemon you’ve caught and trained. Fortunately, with Swift and SwiftUI, you can create a simple Pokemon tracker app that will help you manage your collection. In this blog post, we’ll go through the code for a basic Pokemon tracker app.

Contents 非表示

Model

import Foundation

struct Pokemon: Codable, Identifiable {
    var id: Int
    var name: String
    var type: String
    var level: Int

    init(id: Int, name: String, type: String, level: Int) {
        self.id = id
        self.name = name
        self.type = type
        self.level = level
    }

}

View

import SwiftUI

struct HomeView: View {
    var body: some View {
        PokemonListView()
            .environmentObject(PokemonStore())
    }
}
import SwiftUI

struct AddPokemonView: View {
    @EnvironmentObject var store: PokemonStore
    @State private var name = ""
    @State private var type = ""
    @State private var level = 1
    @Environment(\.presentationMode) var presentationMode //

    var body: some View {
        Form {
            Section(header: Text("Name")) {
                TextField("Enter Pokemon name", text: $name)
            }
            Section(header: Text("Type")) {
                TextField("Enter Pokemon type", text: $type)
            }
            Section(header: Text("Level")) {
                Stepper(value: $level, in: 1...100) {
                    Text("\(level)")
                }
            }
            Button(action: addPokemon) {
                Text("Add Pokemon")
            }
        }
        .navigationBarTitle("Add Pokemon")
    }

    private func addPokemon() {
        // Don't add empty Pokemon
        if name.isEmpty || type.isEmpty {
            return
        }
        let pokemon = Pokemon(id: store.pokemons.count + 1, name: name, type: type, level: level)
        store.pokemons.append(pokemon)
        name = ""
        type = ""
        level = 1
        presentationMode.wrappedValue.dismiss()
    }
}
import SwiftUI

struct PokemonListView: View {
    @EnvironmentObject var store: PokemonStore

    var body: some View {
        NavigationView {
            List(store.pokemons) { pokemon in
                VStack(alignment: .leading, spacing: 10) {
                    Text(pokemon.name)
                        .font(.headline)
                    Text("Type: \(pokemon.type)")
                    Text("Level: \(pokemon.level)")
                }
            }
            .navigationBarTitle("My Pokemon")
            .navigationBarItems(trailing: NavigationLink(destination: AddPokemonView()) {
                Image(systemName: "plus")
            })
        }
    }
}

ViewModel

import SwiftUI

class PokemonStore: ObservableObject {
    @Published var pokemons: [Pokemon] {
        // Save to UserDefaults
        didSet {
            let encoder = JSONEncoder()
            if let encoded = try? encoder.encode(pokemons) {
                UserDefaults.standard.set(encoded, forKey: "pokemons")
            }
        }
    }

    init() {
        // Load from UserDefaults
        if let savedData = UserDefaults.standard.data(forKey: "pokemons") {
            let decoder = JSONDecoder()
            if let loadedData = try? decoder.decode([Pokemon].self, from: savedData) {
                pokemons = loadedData
                return
            }
        }
        pokemons = []
    }
}