質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1181閲覧

構造体の二次元配列を Data型(あるいは NSData型)に変換する方法

sgt.kowalski

総合スコア34

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

2クリップ

投稿2017/09/17 04:50

教えてください!

struct Data { var Count: Int = 0 var PointA: CGPoint = .zero var PointB: CGPoint = .zero var PointC: CGPoint = .zero var Flag: Bool = false }

という構造体があって、これを array という二次元配列に入れています。

array=[[Data]]()

この二次元配列を、最終的には、他の変数と一緒に fileWrapper に詰めて、ひとまとまりのファイルにして書き出したいと思っています。

その際には、この array を Data型(NSData型?)に変換する必要があると思うのですが、その方法が分かりません。

いまは、まず、array を生成したクラス A に下記のコードを書いています。

document.array = array as? NSMutableArray

上記の document は USDocument: UIDocument というクラスを作って、それをインスタンス化したものです。
上記コードは、document 内のメンバー変数 array に、このクラス A で生成した array を渡そうとしているものです。

それを受けて、USDocument クラスでは、渡された array を DATA というキーでアーカイブして fileWrapper に詰めるという処理を書いています。

override func contents(forType typeName: String) throws -> Any { if self.fileWrapper == nil { // 空のDictonaryを渡している self.fileWrapper = FileWrapper(directoryWithFileWrappers:[:]) } if let array = self.array { let data = NSKeyedArchiver.archivedData(withRootObject: array) let fw = FileWrapper(regularFileWithContents: data) fw.preferredFilename = USFileWrapperKeys.DATA self.fileWrapper?.addFileWrapper(fw) } //他の変数を変換して fileWrapper に詰める処理 return self.fileWrapper as Any } }

こんな質問の仕方で適切な回答が得られるのかどうかも自信がないのですが、どうすれば構造体の二次元配列を fileWrapper の一要素として詰めることができるのか、教えてください。

「もっとこういう情報が必要だ」というのがあればお申し付けください。

※上記データ変換を簡単に検証する方法としては、userDefault に保存(=Data型あるいはNSData型に変換)して、それを読み込む(=[Data]の形に復元する)というのを試してみるのがいいのでしょうか?

なにぶん Data型と NSData型の違いもよく分からない初心者なのですが、教えてください。
よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Stripe

2017/09/17 06:05

それで、エラーがでたりするんですか?
sgt.kowalski

2017/09/17 06:43

それを書くのを忘れてました。すみません。libc++abi.dylib: terminating with uncaught exception of type NSExceptionというエラーが出ます。print でチェックしてみると、上記 document.array が nil になっていて、それが原因だとは思うのですが、その解決法が分からず、質問してました。
guest

回答1

0

ベストアンサー

まず、Dataという型の名前はやめましょう。
説明が面倒くさいので以下では

swift

1struct AAA { 2 struct Data { 3 var Count: Int = 0 4 var PointA: CGPoint = .zero 5 var PointB: CGPoint = .zero 6 var PointC: CGPoint = .zero 7 var Flag: Bool = false 8 } 9}

としてるものとします。

また、プロパティ名は小文字から始めるようにしましょう。


NSKeyedArchiver/NSKeyedUnarchiverを使うにはNSCodingプロトコルに準拠する必要があるのですが、NSObjectを継承していないと使えないので、補助的なクラスを利用します。

swift

1class DataCoder: NSObject, NSCoding { 2 3 let data: AAA.Data 4 5 init(data: AAA.Data) { 6 7 self.data = data 8 } 9 10 private struct CodingKey { 11 12 static let countKey = "CountKey" 13 static let pointAKey = "PointAKey" 14 static let pointBKey = "PointBKey" 15 static let PointCKey = "PointCKey" 16 static let flagKey = "FlagKey" 17 } 18 19 required init?(coder aDecoder: NSCoder) { 20 21 let count = aDecoder.decodeInteger(forKey: CodingKey.countKey) 22 let pointA = aDecoder.decodePoint(forKey: CodingKey.pointAKey) 23 let pointB = aDecoder.decodePoint(forKey: CodingKey.pointBKey) 24 let pointC = aDecoder.decodePoint(forKey: CodingKey.PointCKey) 25 let flag = aDecoder.decodeBool(forKey: CodingKey.flagKey) 26 27 self.data = AAA.Data(Count: count, PointA: pointA, PointB: pointB, PointC: pointC, Flag: flag) 28 } 29 30 func encode(with aCoder: NSCoder) { 31 32 aCoder.encode(data.Count, forKey: CodingKey.countKey) 33 aCoder.encode(data.PointA, forKey: CodingKey.pointAKey) 34 aCoder.encode(data.PointB, forKey: CodingKey.pointBKey) 35 aCoder.encode(data.PointC, forKey: CodingKey.PointCKey) 36 aCoder.encode(data.Flag, forKey: CodingKey.flagKey) 37 38 } 39}

このクラスでAAA.Dataを(un)archiveします。

ただし、[[AAA.Data]]を直接扱えませんので、Arrayの中身をそれぞれ(ub)archiveします。

swift

1let data = [[AAA.Data()], [AAA.Data(), AAA.Data()]] 2 3// Archive 4let encodedDataArray = data.map { $0.map { NSKeyedArchiver.archivedData(withRootObject: DataCoder(data: $0)) }} 5let encocedArray = NSKeyedArchiver.archivedData(withRootObject: encodedDataArray) 6 7// Unarchive 8guard let decodedArray = NSKeyedUnarchiver.unarchiveObject(with: encocedArray) as? [[Data]] else { 9 10 fatalError("Can not Decode") 11} 12let decodedDataArray = decodedArray 13 .map { $0.flatMap { NSKeyedUnarchiver.unarchiveObject(with: $0) as? DataCoder } } 14 .map { $0.map { $0.data } }

unarchive時のエラー処理はきちんと入ってませんので、参考まで。

投稿2017/09/17 06:34

MasakiHori

総合スコア3384

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sgt.kowalski

2017/09/17 06:44

ありがとうございます! 「NSCodingプロトコルに準拠」とか、その辺りがさっぱり理解できていないので助かります! 頂いたコードを読み込んでみます!
sgt.kowalski

2017/09/17 17:56

ありがとうございました。 まだ理解が及んでいないのですが、今回は結局、Json化して対応することにしました。 もしかしたら、教えて頂いた方法のほうが効率がいいのかもしれませんが、今の自分の知識レベルで早く実装できる方を選びました。 すみません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問