私の個人アプリを作る流れを全部見せます その11:ドット絵の保存

本企画の全記事はこちらから

今まではダミーのデータで一覧を表示していましたが、ドット絵を保存してそのデータを使うようにします。

Picture構造体

Codableに対応したPictureというStructを使ってデータを保存します。 構造体やCodableについて「Swift 4プログラミング入門」9章で紹介しています。

ドット絵の保存には以下のようなstructを使いました。

Picture.swift
struct Picture: Codable {
    let createdAt: Date
    var dots = [Data]()
    var thumb: Data?

    init(colors: [UIColor]) {
        createdAt = Date()
        self.colors = colors
    }

    var colors: [UIColor] {
        get {
            return dots.map { NSKeyedUnarchiver.unarchiveObject(with: $0) as? UIColor }.flatMap { $0 }
        }
        set {
            dots = newValue.map { NSKeyedArchiver.archivedData(withRootObject: $0) }
        }
    }

    // 省略
}

UIColorがそのままではCodableに対応していないため、Dataに変換しています。

全体のソースコードは以下で閲覧できます。

https://github.com/tnantoka/PixelArtPocket/blob/master/PixelArtPocket/Picture.swift

新規追加・一覧表示

先程の構造体を使って一覧を表示します。 ここでは、プラスボタンをタップするとデータを追加し、テーブルビューを再読込することで実装しています。

IndexViewController.swift
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)

        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .short

        let picture = pictures[indexPath.row]

        cell.textLabel?.text = formatter.string(from: picture.createdAt)
        cell.imageView?.image = picture.image

        return cell
    }

    @IBAction func onTapAdd(_ sender: Any) {
        let picture = Picture(colors: EditorView.defaultDots)
        picture.save()
        reload()
    }

    func reload() {
        pictures = Picture.all
        tableView.reloadData()
    }

構造体の箇所では省略しましたが、allは全データを読み込んで配列で返す静的メソッドで、saveメソッドは現在のPictureをJSONデータとして保存するメソッドです。

この状態で実行してみると、一覧の動作が確認できました。

保存したデータを使う

あとは、一覧から編集画面に遷移する時に、保存したPictureを使うようにすればOKです。

IndexViewController.swift
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let picture = pictures[indexPath.row]
        performSegue(withIdentifier: "edit", sender: picture)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let picture = sender as? Picture {
            (segue.destination as? EditViewController)?.picture = picture
        }
    }
EditViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()

        guard let picture = picture else { return }
        editorView.dots = picture.colors

        // Do any additional setup after loading the view.
        editorView.dotsDidChange = {
            self.undoItem.isEnabled = self.editorView.canUndo
            self.redoItem.isEnabled = self.editorView.canRedo
            self.picture?.colors = self.editorView.dots
            self.picture?.image = self.editorView.screenshot
            self.picture?.save()
    }

こんな感じでセグエ呼び出しの際に渡して、ドット絵が変更されるたびにpictureを保存しています。

保存した画像をテーブルビューのimageにも表示してあげるとそれっぽくなりました。

ドットを変更するたびに保存するのは負荷が高そうなのでもう少し効率化したいところですが、機能としては期待どおりに動いているのでこの状態で先に進みます。

この状態のプロジェクトのダウンロードはこちらから。

https://github.com/tnantoka/PixelArtPocket/releases/tag/my-app-dev-flow-11