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

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

ただいまの
回答率

90.47%

  • Swift

    7463questions

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

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

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 727

sgt.kowalski

score 24

教えてください!

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型の違いもよく分からない初心者なのですが、教えてください。
よろしくお願い致します。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Stripe

    2017/09/17 15:05

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

    キャンセル

  • sgt.kowalski

    2017/09/17 15:43

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

    キャンセル

回答 1

checkベストアンサー

0

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

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

としてるものとします。

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


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

class DataCoder: NSObject, NSCoding {

    let data: AAA.Data

    init(data: AAA.Data) {

        self.data = data
    }

    private struct CodingKey {

        static let countKey = "CountKey"
        static let pointAKey = "PointAKey"
        static let pointBKey = "PointBKey"
        static let PointCKey = "PointCKey"
        static let flagKey = "FlagKey"
    }

    required init?(coder aDecoder: NSCoder) {

        let count = aDecoder.decodeInteger(forKey: CodingKey.countKey)
        let pointA = aDecoder.decodePoint(forKey: CodingKey.pointAKey)
        let pointB = aDecoder.decodePoint(forKey: CodingKey.pointBKey)
        let pointC = aDecoder.decodePoint(forKey: CodingKey.PointCKey)
        let flag = aDecoder.decodeBool(forKey: CodingKey.flagKey)

        self.data = AAA.Data(Count: count, PointA: pointA, PointB: pointB, PointC: pointC, Flag: flag)
    }

    func encode(with aCoder: NSCoder) {

        aCoder.encode(data.Count, forKey: CodingKey.countKey)
        aCoder.encode(data.PointA, forKey: CodingKey.pointAKey)
        aCoder.encode(data.PointB, forKey: CodingKey.pointBKey)
        aCoder.encode(data.PointC, forKey: CodingKey.PointCKey)
        aCoder.encode(data.Flag, forKey: CodingKey.flagKey)

    }
}

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

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

let data = [[AAA.Data()], [AAA.Data(), AAA.Data()]]

// Archive
let encodedDataArray = data.map { $0.map { NSKeyedArchiver.archivedData(withRootObject: DataCoder(data: $0)) }}
let encocedArray = NSKeyedArchiver.archivedData(withRootObject: encodedDataArray)

// Unarchive
guard let decodedArray = NSKeyedUnarchiver.unarchiveObject(with: encocedArray) as? [[Data]] else {

    fatalError("Can not Decode")
}
let decodedDataArray = decodedArray
    .map { $0.flatMap { NSKeyedUnarchiver.unarchiveObject(with: $0) as? DataCoder } }
    .map { $0.map { $0.data } }

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/17 15:44

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

    キャンセル

  • 2017/09/18 02:56

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

    すみません。

    キャンセル

関連した質問

同じタグがついた質問を見る

  • Swift

    7463questions

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