SwiftUIで学ぶ!ローカル&APIデータ管理入門

Swift

はじめに

iOSアプリ開発では、ローカルデータの保存と外部APIからのデータ取得が重要です。本記事では、UserDefaultsでの簡単なローカルデータ管理から、URLSessionを使ったAPIのデータ取得、さらにデータ管理におけるアーキテクチャ設計の基礎までを学びます。

ローカルデータの保存

UserDefaults の使い方

UserDefaultsは、小規模なデータを保存するのに適したキー・バリュー型のデータ保存機能です。

データの保存

UserDefaultsを使ってデータを保存するには、set(_:forKey:)メソッドを使用します。

Swift
// String型のデータを保存
UserDefaults.standard.set("Hello, Swift!", forKey: "greetingKey")

// Int型のデータを保存
UserDefaults.standard.set(42, forKey: "numberKey")

// Bool型のデータを保存
UserDefaults.standard.set(true, forKey: "isEnabledKey")

// Array型のデータを保存
UserDefaults.standard.set(["Item1", "Item2"], forKey: "arrayKey")

// Dictionary型のデータを保存
UserDefaults.standard.set(["key1": "value1", "key2": "value2"], forKey: "dictionaryKey")

データの取得

保存したデータを取得するには、適切な型にキャストして取り出します。

Swift
// String型のデータを取得
if let greeting = UserDefaults.standard.string(forKey: "greetingKey") {
    print(greeting) // Hello, Swift!
}

// Int型のデータを取得
let number = UserDefaults.standard.integer(forKey: "numberKey")
print(number) // 42

// Bool型のデータを取得
let isEnabled = UserDefaults.standard.bool(forKey: "isEnabledKey")
print(isEnabled) // true

// Array型のデータを取得
if let items = UserDefaults.standard.array(forKey: "arrayKey") as? [String] {
    print(items) // ["Item1", "Item2"]
}

// Dictionary型のデータを取得
if let dictionary = UserDefaults.standard.dictionary(forKey: "dictionaryKey") {
    print(dictionary) // ["key1": "value1", "key2": "value2"]
}

データの削除

保存したデータを削除するには、removeObject(forKey:)を使用します。

Swift
UserDefaults.standard.removeObject(forKey: "greetingKey")

注意点

  • 小規模なデータ(設定値やフラグ)に適しており、大量データには向きません。

実装例:ローカルの設定データを管理

以下は、スイッチの状態を保存する例です

Swift
import SwiftUI

struct UserDefaultsExample: View {
    @State private var isSwitchOn = UserDefaults.standard.bool(forKey: "switchState")

    var body: some View {
        Toggle("Switch", isOn: $isSwitchOn)
            .onChange(of: isSwitchOn) { newValue in
                UserDefaults.standard.set(newValue, forKey: "switchState")
            }
            .padding()
    }
}

API の使用

外部データを取得するには、URLSessionを使ってネットワークリクエストを送信します。

URLSession を使ったデータ取得

GETリクエスト

Swift
URLSession.shared.dataTask(with: URL(string: "https://example.com")!).resume()

POSTリクエスト

Swift
var req = URLRequest(url: URL(string: "https://example.com")!); 
req.httpMethod = "POST"; 
req.httpBody = Data(); 
URLSession.shared.dataTask(with: req).resume()

PUTリクエスト

Swift
var req = URLRequest(url: URL(string: "https://example.com")!);
req.httpMethod = "PUT";
req.httpBody = Data();
URLSession.shared.dataTask(with: req).resume()

DELETEリクエスト

Swift
var req = URLRequest(url: URL(string: "https://example.com")!);
req.httpMethod = "DELETE"; 
URLSession.shared.dataTask(with: req).resume()

APIからJSONデータを取得する例

APIエンドポイントを用意
  • OpenWeatherMap APIのURL例
Plaintext
https://api.openweathermap.org/data/2.5/weather?q=London&appid=YOUR_API_KEY
データ取得コード
Swift
import SwiftUI

struct WeatherData: Codable {
    let name: String
    let main: Main
}

struct Main: Codable {
    let temp: Double
}

class WeatherViewModel: ObservableObject {
    @Published var cityName: String = ""
    @Published var temperature: Double = 0.0

    func fetchWeather(for city: String) {
        guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(city)&appid=YOUR_API_KEY&units=metric") else { return }

        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else { return }
            do {
                let weather = try JSONDecoder().decode(WeatherData.self, from: data)
                DispatchQueue.main.async {
                    self.cityName = weather.name
                    self.temperature = weather.main.temp
                }
            } catch {
                print("Error decoding: \(error)")
            }
        }.resume()
    }
}

データ管理

MVC または MVVM の基礎

  • MVC(Model-View-Controller)
    シンプルな設計で、小規模なアプリに適しています。
    • Model: データやロジック。
    • View: UIを構築。
    • Controller: ロジックとUIの橋渡し。
  • MVVM(Model-View-ViewModel)
    SwiftUIに適しており、データの双方向バインディングを簡単に扱えます。
    • Model: データ。
    • View: UIを構築。
    • ViewModel: データロジックを管理し、ViewとModelをつなぐ。

Combine を使ったリアクティブプログラミング(任意)

Combineを使用すると、データの変化をリアルタイムでUIに反映できます。

例: Combineを使ったデータバインディング

Swift
import Combine
import SwiftUI

class WeatherViewModel: ObservableObject {
    @Published var temperature: Double = 0.0

    func updateTemperature(newTemp: Double) {
        DispatchQueue.main.async {
            self.temperature = newTemp
        }
    }
}

ミニプロジェクト:天気予報アプリ

目標

  • ユーザーが都市名を入力すると、天気データを取得して表示。

完成コード

Swift
import SwiftUI

// WeatherViewModel: 天気データを管理するクラス
class WeatherViewModel: ObservableObject {
    @Published var cityName: String = ""
    @Published var temperature: Double = 0.0

    func fetchWeather(for city: String) {
        guard !city.isEmpty else {
            print("City name is empty")
            return
        }

        // OpenWeatherMap API URL
        let apiKey = "YOUR_API_KEY" // 必ずAPIキーを取得して置き換えてください
        let urlString = "https://api.openweathermap.org/data/2.5/weather?q=\(city)&appid=\(apiKey)&units=metric"

        guard let url = URL(string: urlString) else {
            print("Invalid URL")
            return
        }

        // URLSessionでリクエスト
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                print("Error fetching weather data: \(error.localizedDescription)")
                return
            }

            guard let data = data else {
                print("No data received")
                return
            }

            do {
                // JSONデコード
                let weather = try JSONDecoder().decode(WeatherData.self, from: data)
                DispatchQueue.main.async {
                    self.cityName = weather.name
                    self.temperature = weather.main.temp
                }
            } catch {
                print("Error decoding JSON: \(error.localizedDescription)")
            }
        }.resume()
    }
}

// WeatherData: APIレスポンス用のモデル
struct WeatherData: Codable {
    let name: String
    let main: Main
}

struct Main: Codable {
    let temp: Double
}

// ContentView: アプリのUIを構築
struct ContentView: View {
    @StateObject private var viewModel = WeatherViewModel()
    @State private var city = ""

    var body: some View {
        VStack {
            // 都市名の入力
            TextField("Enter city name", text: $city)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()

            // 天気取得ボタン
            Button("Get Weather") {
                viewModel.fetchWeather(for: city)
            }
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(10)

            // 天気データの表示
            if !viewModel.cityName.isEmpty {
                Text("City: \(viewModel.cityName)")
                    .font(.title)
                Text("Temperature: \(viewModel.temperature, specifier: "%.1f")°C")
                    .font(.largeTitle)
            }

            Spacer()
        }
        .padding()
    }
}

アプリの機能説明

  1. 都市名の入力
    • ユーザーが都市名を入力し、「Get Weather」ボタンを押すとAPIリクエストが送信されます。
  2. データの取得と表示
    • WeatherViewModelがAPIから取得したデータを処理し、画面に表示します。

まとめ

今回の記事では、以下を学びました

  • ローカルデータの保存: UserDefaultsの基本。
  • APIの使用: URLSessionで外部データを取得。
  • データ管理の設計: MVVMを使った効率的なアーキテクチャ。

天気予報アプリを作成することで、データ管理とネットワーク操作の基礎を習得できました。次は、エラーハンドリングやデータ保存機能を追加してみましょう!

コメント

タイトルとURLをコピーしました