[Swift] Header - Items形式のデータの読み書きを行う
ヘッダデータ[1]と明細データ[0...n]を1つのデータの塊として、
ファイルに保存したり、読み込んだりしたくて、試行錯誤しました。
DBにした方が楽なんじゃない? とか思ったけど、DBにするほどデータも無かったので 、意地でもファイルで実現してやる!
ってことで、なんとか動きました。
<ヘッダデータ> [1]
伝票番号 orderNo
仕入先コード vendorCode
仕入先名 vendorName
<明細データ> [0...1]
明細番号 itemNo
明細テキスト itemText
数量 quantity
ヘッダは必ず存在し、明細は0以上の可変を想定。
キーはStringで良いと思いますが、値は、String、Int、Item構造型など、様々な型があるので、AnyObjectとしました。
ヘッダデータは、キーと値を単純にセットしてます。
これにより明細数を動的にしてます。
Array配列の明細データを作り上げてから、ヘッダデータを格納した Dictionary型の変数に格納してます。
データは、アプリのDocuments内に、Test.plistで保存してます。
ヘッダデータは、キー指定で値を取り出してます。
nilの場合(キー値が存在しない場合)は、何もせず初期値のままとするため、nilの判定を入れてます。
明細データは、Array配列として一旦取り込んでから、1件毎に明細データの取り出しを行ってます。
配列は、0件の場合もあるため、nil判定を行ってます。
forループで明細データを1件毎 取り出してます。
ファイルからの読み込み値を検証するために、一旦、変数を初期化してます。
その後、データ内容をファイルから読み込む関数(readData)を呼び出してます。
取り込んだデータは、UITextViewに出力してます。
実装の参考になれば幸いです。
ファイルに保存したり、読み込んだりしたくて、試行錯誤しました。
DBにした方が楽なんじゃない? とか思ったけど、DBにするほどデータも無かったので 、意地でもファイルで実現してやる!
ってことで、なんとか動きました。
扱うデータのイメージ
<ヘッダデータ> [1]
伝票番号 orderNo
仕入先コード vendorCode
仕入先名 vendorName
<明細データ> [0...1]
明細番号 itemNo
明細テキスト itemText
数量 quantity
ヘッダは必ず存在し、明細は0以上の可変を想定。
データ受け渡し用の構造
struct DataEntity { // Header var orderNo: Int! var vendorCode: String! var vendorName: String! // Items var items: [Item]! init(){ orderNo = 0 vendorCode = "" vendorName = "" items = [] } } struct Item { var itemNo: Int! var itemText: String! var quantity: Int! init(){ itemNo = 0; itemText = "" quantity = 0 } }
コード
データをファイルに保存する
func writeData(dataEntity: DataEntity){ var data:Dictionary = [String:AnyObject]() // Header data["orderNo"] = dataEntity.orderNo as AnyObject data["vendorCode"] = dataEntity.vendorCode as AnyObject data["vendorName"] = dataEntity.vendorName as AnyObject // Items var dataItem :Dictionary = [String:Any]() var dataItems:Array= [] for item in dataEntity.items { dataItem.removeAll() dataItem["itemNo"] = item.itemNo dataItem["itemText"] = item.itemText dataItem["quantity"] = item.quantity dataItems.append(dataItem as AnyObject) } data["items"] = dataItems as AnyObject // ファイルへ書き込み let manager = FileManager.default let documentDir = manager.urls(for: .documentDirectory, in: .userDomainMask)[0] let url = documentDir.appendingPathComponent("Test.plist") let dic = NSDictionary(dictionary: data) dic.write(to: url, atomically: true) }
説明
Dictionary型を使うと便利そうだったでので、こちらを使ってます。キーはStringで良いと思いますが、値は、String、Int、Item構造型など、様々な型があるので、AnyObjectとしました。
var data:Dictionary = [String:AnyObject]()
ヘッダデータは、キーと値を単純にセットしてます。
// Header data["orderNo"] = dataEntity.orderNo as AnyObject data["vendorCode"] = dataEntity.vendorCode as AnyObject data["vendorName"] = dataEntity.vendorName as AnyObject明細については、明細データをDictionary型で格納し、Dictionary型をArray配列に格納てます。
これにより明細数を動的にしてます。
// Items var dataItem :Dictionary = [String:Any]() var dataItems:Array= [] for item in dataEntity.items { dataItem.removeAll() dataItem["itemNo"] = item.itemNo dataItem["itemText"] = item.itemText dataItem["quantity"] = item.quantity dataItems.append(dataItem as AnyObject) }
Array配列の明細データを作り上げてから、ヘッダデータを格納した Dictionary型の変数に格納してます。
data["items"] = dataItems as AnyObject
データは、アプリのDocuments内に、Test.plistで保存してます。
ファイルからデータを読み込む
func readData() -> DataEntity { // ファイル読み込み let manager = FileManager.default let documentDir = manager.urls(for: .documentDirectory, in: .userDomainMask)[0] let url = documentDir.appendingPathComponent("Test.plist") let plist = NSMutableDictionary(contentsOf: url) var dataEntity = DataEntity() if plist == nil { return dataEntity } // Header if let _orderNo = plist?["orderNo"] as? Int { dataEntity.orderNo = _orderNo } if let _vendorCode = plist?["vendorCode"] as? String { dataEntity.vendorCode = _vendorCode } if let _vendorName = plist?["vendorName"] as? String { dataEntity.vendorName = _vendorName } // Items if let _items = plist?["items"] as? Array{ let dataItems = _items for dataItem in dataItems { var item = Item() if let _itemNo = dataItem["itemNo"] as? Int { item.itemNo = _itemNo } if let _itemText = dataItem["itemText"] as? String { item.itemText = _itemText } if let _quantity = dataItem["quantity"] as? Int { item.quantity = _quantity } dataEntity.items.append(item) } } return dataEntity }
説明
アプリ内のDocumentsフォルダ内のTest.plistファイルを読み込みます。ヘッダデータは、キー指定で値を取り出してます。
nilの場合(キー値が存在しない場合)は、何もせず初期値のままとするため、nilの判定を入れてます。
if let _orderNo = plist?["orderNo"] as? Int { dataEntity.orderNo = _orderNo }
明細データは、Array配列として一旦取り込んでから、1件毎に明細データの取り出しを行ってます。
配列は、0件の場合もあるため、nil判定を行ってます。
if let _items = plist?["items"] as? Array{
forループで明細データを1件毎 取り出してます。
for dataItem in dataItems {
サンプルコード(全体)
import UIKit class ViewController: UIViewController { let txtView = UITextView() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.view.backgroundColor = UIColor.lightGray txtView.frame = self.view.frame view.addSubview(txtView) // ----------------------------- var data = DataEntity() // Test Data data.orderNo = 100 data.vendorCode = "VEN-123" data.vendorName = "Test Vendor Name" var item = Item() // item 1 item.itemNo = 10 item.itemText = "Item Text 1" item.quantity = 2 data.items.append(item) // item 2 item.itemNo = 20 item.itemText = "Item Text 2" item.quantity = 7 data.items.append(item) // Write to File writeData(dataEntity: data) // ----------------------------- // Initialize data = DataEntity() // Read from File data = readData() txtView.text.append("Order = " + String(data.orderNo) + "\n") txtView.text.append("Vendor Code = " + data.vendorCode + "\n") txtView.text.append("Vendor Name = " + data.vendorName + "\n") for item in data.items { txtView.text.append("----------\n") txtView.text.append("ItemNo: " + String(item.itemNo) + "\n") txtView.text.append("Item Text: " + item.itemText + "\n") txtView.text.append("Quantity: " + String(item.quantity) + "\n") } } func writeData(dataEntity: DataEntity){ var data:Dictionary = [String:AnyObject]() // Header data["orderNo"] = dataEntity.orderNo as AnyObject data["vendorCode"] = dataEntity.vendorCode as AnyObject data["vendorName"] = dataEntity.vendorName as AnyObject // Items var dataItem :Dictionary = [String:Any]() var dataItems:Array= [] for item in dataEntity.items { dataItem.removeAll() dataItem["itemNo"] = item.itemNo dataItem["itemText"] = item.itemText dataItem["quantity"] = item.quantity dataItems.append(dataItem as AnyObject) } data["items"] = dataItems as AnyObject // ファイルへ書き込み let manager = FileManager.default let documentDir = manager.urls(for: .documentDirectory, in: .userDomainMask)[0] let url = documentDir.appendingPathComponent("Test.plist") let dic = NSDictionary(dictionary: data) dic.write(to: url, atomically: true) } func readData() -> DataEntity { // ファイル読み込み let manager = FileManager.default let documentDir = manager.urls(for: .documentDirectory, in: .userDomainMask)[0] let url = documentDir.appendingPathComponent("Test.plist") let plist = NSMutableDictionary(contentsOf: url) var dataEntity = DataEntity() if plist == nil { return dataEntity } // Header if let _orderNo = plist?["orderNo"] as? Int { dataEntity.orderNo = _orderNo } if let _vendorCode = plist?["vendorCode"] as? String { dataEntity.vendorCode = _vendorCode } if let _vendorName = plist?["vendorName"] as? String { dataEntity.vendorName = _vendorName } // Items if let _items = plist?["items"] as? Array { let dataItems = _items for dataItem in dataItems { var item = Item() if let _itemNo = dataItem["itemNo"] as? Int { item.itemNo = _itemNo } if let _itemText = dataItem["itemText"] as? String { item.itemText = _itemText } if let _quantity = dataItem["quantity"] as? Int { item.quantity = _quantity } dataEntity.items.append(item) } } return dataEntity } }
実行結果
説明
パラメータをセットしてファイル書き込み用の関数(writeData)を呼び出してます。ファイルからの読み込み値を検証するために、一旦、変数を初期化してます。
その後、データ内容をファイルから読み込む関数(readData)を呼び出してます。
取り込んだデータは、UITextViewに出力してます。
最後に
エラーハンドリングなど甘いところはあると思いますが、実装の参考になれば幸いです。
コメント
コメントを投稿