【アプリ開発時】IGListKit + RxSwift + ReSwift 【エラー内容記録】
workingRangeSize のエラー
エラー内容
- Value of type 'ListAdapter' has no member 'workingRangeSize'
原因
- 『workingRangeSize はプロパティではなく“イニシャライザ引数”』だからです。
- ListAdapter 生成後に adapter.workingRangeSize = 1 と代入する API は存在しません。
- 生成時に渡すか、未使用なら 0(デフォルト)に変更してください。
解決
- IGListAdapterProvider を生成時指定に変更。
- 呼び出し側:IGListHostingViewController の init()も、viewController: self と workingRangeSize を渡します。
- workingRangeSize は イニシャライザ引数で指定、performUpdates は async なので Task で呼び出しています)。
workingRange とは?
- 一言で言うと、workingRange は adapter の“挙動そのもの”を決める根本設定だからです。
- 途中でコロコロ変えると、レンジ出入りイベント(先読み通知)の整合性が壊れやすいので、生成時に一度だけ決める設計になっています。
API 設計として『変わらない』
- ListAdapter は 初期化時の引数で workingRangeSize を受け取る形。
- 使わないなら 0、使うなら値を渡す、という二択が Constructor で明示されます(0 を渡すか、workingRange 無しのイニシャライザを使う)。
workingRange は“画面外位置の近い範囲”を制御する
- 画面に見える要素の前後何個までを『位置の近い範囲』とみなして、事前読み込みやデコードを始めるための仕組みです。
- どの範囲を位置が近いとするかは RangeSize に依存し、これを途中で変えると enter/exit に通知される順序が狂うため、初期化時に確定させます。
async とは?
- ざっくり言うと UI の差分 → バッチ更新 → アニメーションの完了までが“非同期の一連の処理”だからです。
- IGListKit はそれを async/await で表現しています。
実務におけるメリットは?
- 更新の直列化:await adapter.performUpdates(...) の直後に“更新後のインデックス”を前提とした処理を書ける。
- 競合回避:連続更新やスクロール中更新でも、前回のアニメ完了を待って次へ。
【第1部】SwiftUIで作る日本の気温マップアプリ - 設計とアーキテクチャ編
概要
今回は、SwiftUIを使って日本各地の気温情報をインタラクティブに表示するiOSアプリの実装について、3回シリーズで解説します。このアプリは教育・デモンストレーション目的で作成されており、実際の気象データではなくサンプルデータを使用しています。
第1部では、アプリの全体設計とアーキテクチャについて詳しく解説します。
アプリの主要機能
このアプリは以下の機能を提供します:
- 日本9地方の気温データ表示: 北海道から沖縄まで各地方の気温情報
- 統計情報の自動計算: 平均・最高・最低気温、猛暑地域数の算出
- 温度に応じた4段階の色分け表示: 視覚的な温度分類
- インタラクティブなテーブル操作: タップによる詳細情報表示
- データ操作機能: 更新・ソート機能
アーキテクチャ設計
MVVMパターンの採用
アプリ全体でMVVM(Model-View-ViewModel)パターンを採用し、SwiftUIの@ObservableObjectを使用してデータの状態管理を行っています。
class TemperatureDataManager: ObservableObject { @Published var regions: [RegionData] = [] @Published var selectedRegion: RegionData? @Published var lastUpdate: Date = Date() @Published var sortOrder: SortOrder = .geographic enum SortOrder { case geographic case temperature } }
この設計により、以下のメリットを実現しています:
- 関心の分離: データ管理とUI表示の責任を明確に分離
- テスタビリティ: ビジネスロジックを独立してテスト可能
- 保守性: 各層の変更が他の層に影響しにくい構造
データモデルの設計
RegionData構造体
地方データを表現する基本的な構造体です:
struct RegionData { let name: String let temps: [Int] let comments: [String] var currentTemp: Int var currentComment: String mutating func updateTemperature() { self.currentTemp = temps.randomElement() ?? 20 self.currentComment = comments.randomElement() ?? "" } }
設計のポイント:
- 不変性の活用: name、temps、commentsはletで定義し、データの整合性を保護
- ランダム選択: randomElement()を使用して安全にランダム値を取得
- デフォルト値: nil coalescingでクラッシュを防止
TemperatureStats構造体
統計情報を管理する構造体です:
struct TemperatureStats { let average: Int let max: Int let min: Int let hotRegions: Int }
特徴: - Value Type: 構造体として定義し、値セマンティクスを活用 - 計算専用: データを保持するのみで、計算ロジックは別で管理 - 型安全: 全てInt型で統一し、型変換エラーを防止
データ管理層の責務
TemperatureDataManagerクラスは以下の責務を持ちます:
1. データ初期化
private func initializeData() { regions = [ RegionData(name: "北海道", temps: [18, 22, 24, 26, 20], comments: ["涼しく過ごしやすい", "散歩日和", "軽装で快適", "外出に最適", "涼しい一日"]), RegionData(name: "東北", temps: [25, 27, 29, 24, 26], comments: ["適度な暖かさ", "外出に最適", "少し暑め", "過ごしやすい", "快適な気温"]), // ... 他の地方のデータ ] }
2. 統計計算
func getStats() -> TemperatureStats { let temps = regions.map { $0.currentTemp } let average = temps.reduce(0, +) / temps.count let max = temps.max() ?? 0 let min = temps.min() ?? 0 let hotRegions = temps.filter { $0 > 35 }.count return TemperatureStats(average: average, max: max, min: min, hotRegions: hotRegions) }
3. データ更新
func updateAllTemperatures() { for i in 0..<regions.count { regions[i].updateTemperature() } lastUpdate = Date() }
アーキテクチャの利点
1. 単一責任原則の遵守
各クラス・構造体が明確な責任を持ち、変更理由が限定されています。
2. 依存関係の管理
- View → ViewModel → Model の単方向依存
- 循環参照の回避
- テスト時のモック化が容易
3. SwiftUIとの親和性
@Publishedによる自動UI更新@ObservableObjectによる状態管理- SwiftUIのデータフローに最適化
拡張性の考慮
プロトコル指向設計への発展
現在の実装を以下のようにプロトコル化することで、さらなる拡張性を実現できます:
protocol TemperatureDataSource { func updateAllTemperatures() func sortByTemperature() func sortByRegion() func getStats() -> TemperatureStats } protocol RegionDataProtocol { var name: String { get } var currentTemp: Int { get set } var currentComment: String { get set } mutating func updateTemperature() }
将来の拡張可能性
- リアルタイムデータ対応: 気象APIとの連携
- データ永続化: Core DataやUserDefaultsとの統合
- 通知機能: 気温変化の通知システム
- カスタマイズ: ユーザー設定による表示カスタマイズ
定数管理戦略
アプリ全体で使用する定数を一箇所で管理しています:
struct AppConstants { static let regionOrder = ["北海道", "東北", "関東", "中部", "関西", "中国", "四国", "九州", "沖縄"] struct TemperatureThresholds { static let cool = 20 static let warm = 28 static let hot = 35 } struct UI { static let cornerRadius: CGFloat = 15 static let cardPadding: CGFloat = 15 static let standardSpacing: CGFloat = 20 } }
定数管理の利点: - 保守性: 値の変更が一箇所で済む - 一貫性: アプリ全体で統一された値を使用 - 可読性: 意味のある名前で定数を管理
まとめ
第1部では、SwiftUIアプリケーションにおけるMVVMアーキテクチャの実装方法と、データモデルの設計について解説しました。
主要なポイント:
- MVVMパターンによる明確な責任分離
- SwiftUIの@ObservableObjectを活用したリアクティブな状態管理
- 型安全性とエラーハンドリングを考慮したデータモデル設計
- 拡張性を意識した構造設計
次回の第2部では、実際のUI実装とコンポーネント設計について詳しく解説します。特に、温度による視覚的表現の実装方法と、再利用可能なUIコンポーネントの設計パターンを中心に説明します。
関連記事 - [第2部] UI実装とコンポーネント編(次回公開予定) - [第3部] テストと技術特徴編(第3回公開予定)
React TODOリストアプリの完全解説:基本機能から包括的テストまで
概要
このTODOリストアプリケーションは、Reactの基本概念を学習するのに最適な実装となっています。シンプルながらも実用的な機能を備え、包括的なテストケースによって品質が保証されています。
続きを読む