Property List (plist)ファイルで定義した配列をUITableViewで表示したいという質問に回答しました。
私もObjective-C
を使っていた時代にplistで表示項目のON/OFFの切り替えを管理していた時期を思い出しました。あの頃は PropertyListDecoder
がなくて、plistファイルをNSArrayまたはNSDictionaryで管理する必要があり、データのパースには頭を悩ませました。
Swift 4にて PropertyListDecoder
が追加され、これが思った以上に便利でしたので 、本記事では plistファイルをPropertyListDecoderを使ってデシリアライズする方法を紹介します。
Property Listを以下の通り定義している
まず、plistはセクションを分けて表示できるように大きく「セクション1」と「セクション2」で分けています。
本来であればNSArrayなりを使って自前でパースする必要があります。
モデルの型を定義する
下記のようにstruct型を定義しておきます。ItemGroup型とItemData型のプロパティで定義した名前とplist側のkey名とを一致させるようにしておいてください。
struct ItemData: Decodable { let name: String let imageName: String } struct ItemGroup: Decodable { let sectionTitle: String let items: [ItemData] }
PropertyListDecoderを使って指定したplistファイルを先ほど定義したモデルにマッピングします。
if let path = Bundle.main.path(forResource: "Items", ofType:"plist" ) { let data = try! Data(contentsOf: URL(fileURLWithPath: path)) items = try! PropertyListDecoder().decode([ItemGroup].self, from: data) }
パースしたデータをUITableViewで表示する
画面側では以下のように、Items.plist を読み出して PropertyListDecoder
を使ってItemGroup型へデシリアライズします。
class ViewController: UITableViewController { var items: [ItemGroup] = [] override func viewDidLoad() { super.viewDidLoad() if let path = Bundle.main.path(forResource: "Items", ofType:"plist" ) { let data = try! Data(contentsOf: URL(fileURLWithPath: path)) items = try! PropertyListDecoder().decode([ItemGroup].self, from: data) } } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return items.count } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items[section].items.count } override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return items[section].sectionTitle } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let item = items[indexPath.section].items[indexPath.row] let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = item.name cell.imageView?.image = UIImage(named: item.imageName) return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let item = items[indexPath.section].items[indexPath.row] print("item: \(item.name)") } }
上記のコードを実行すると下図のように表示されます。
サンプルプロジェクト
Xcode 11.6 (iOS 13.6)時点で実行可能なサンプルプロジェクトを GitHub へアップロードしておきました。