Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法

ここでは、Swift で画像ファイルをデバイスの Document Directory に保存・取得する方法をご説明します。

前回 「カメラで写真を撮る方法」で、Take Photo というボタンをタップした時に、カメラが起動して写真を撮り、元の画面に撮った写真が表示されるアプリを作りました。

今回はそのアプリに Save Photo、Clear Photo、Load Photo の三つのボタンを追加して、画像ファイルをデバイスの Document Directory に保存・取得する機能を追加します。

写真を撮る iOS アプリにボタンとアクションを追加する

まずは、カメラで写真を撮る iOS アプリに、今回テストに使う三つのボタンを追加して、アクションを作っておきます。

カメラで写真を撮る iOS アプリをまだ作っていない方は「カメラで写真を撮る方法」を参考に作っておいてください。

プロジェクトを開き、Main ストーリーボードの View Controller の Take Photo ボタンの下に、Save Photo、Clear Photo、Load Photo の三つのボタンを追加します。

ここでは Stack View に入れていますが、配置や色など、適当で大丈夫です。

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 1


Save Photo、Clear Photo、Load Photo ボタンから、それぞれ、savePhotoTapped、clearPhotoTapped、loadPhotoTapped という名前で TouchUpInside のアクションを作っておきます。

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 2

@IBAction func savePhotoTapped(_ sender: Any) {
}

@IBAction func clearPhotoTapped(_ sender: Any) {
}

@IBAction func loadPhotoTapped(_ sender: Any) {
}

Clear Photo ボタンをタップした時には、UIImageView の画像を削除したいので、次の一行のコードを追加しておきます。

imageView は UIImageView のアウトレットです。

@IBAction func clearPhotoTapped(_ sender: Any) {
    imageView.image = nil
}

Swift で画像ファイルを Document Directory に保存する方法

Swift でデバイスのユーザーの Document Directory に UIImageView に表示されている写真を保存します。


Save Photo ボタンをタップした時に、UIImageView の image を保存するコードを書きます。

ViewController.swift に getFileURL() を追加し、先ほど作った savePhotoTapped() を次のように変更します。

func getFileURL(fileName: String) -> URL {
    let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    return docDir.appendingPathComponent(fileName)
}

@IBAction func savePhotoTapped(_ sender: Any) {
    guard let imageData = imageView.image?.jpegData(compressionQuality: 1.0) else {
        return
    }

    do {
        try imageData.write(to: getFileURL(fileName: "IMG12345.jpg"))
        print("Image saved.")
    } catch {
        print("Failed to save the image:", error)
    }
}

getFileURL() は fileName を受け取って、documentDirectory の、そのファイルの URL を返す関数です。

2 行目の FileManager.default.urls() で、指定したドメインの共通ディレクトリの URL を取得します。

今回は、for: .documentDirectory, in: .userDomainMask と引数を指定することで、ユーザーのドキュメントディレクトリの URL 取得しています。

userDomainMask は、ユーザーのホームディレクトリで、ユーザーのファイルなどを保存できる領域です。

そして、urls() メソッドは URL の配列を返すので、ひとつめの URL を取得しています。

3 行目 で、appendingPathComponent() を使って、パスにファイル名を追加して、その URL を返してします。


次に、savePhotoTapped() 内のコードを説明します。

7 行目では、guard let で imageView(UIImageView のアウトレット)から jpegData 取得し、もし取得できなかったら return しています。

compressionQuality は 0.0 ~ 1.0 で指定でき、0.0 が一番圧縮される&低クオリティ、1.0 が一番圧縮されない&高クオリティになります。

12 行目で Data の write() メソッドを使って、画像データをユーザーのドキュメントディレクトリに保存しています。

今回はファイル名は固定で IMG12345.jpg にしています。

画像ファイルをユーザーの Document Directory に保存するコードは以上です。

Swift で画像ファイルを Document Directory から取得する方法

次は、Swift でデバイスのユーザーの Document Directory に保存されている画像ファイルから画像データを取得します。


Load Photo ボタンをタップした時に、ユーザーの Document Directory 保存した画像ファイルを読み込み、UIImageView に表示するコードを書きます。

ViewController.swift の loadPhotoTapped() を次のように変更します。

@IBAction func loadPhotoTapped(_ sender: Any) {
    let path = getFileURL(fileName: "IMG12345.jpg").path

    if FileManager.default.fileExists(atPath: path) {
        if let imageData = UIImage(contentsOfFile: path) {
            imageView.image = imageData
        }
        else {
            print("Failed to load the image.")
        }
    }
    else {
        print("Image file not found.")
    }
}

2 行目では、先ほど保存した画像ファイル IMG12345.jp の URL の path を取得しています。

4 行目の FileManager.default.fileExists() で path のファイルが存在するか確認し、存在していれば、UIImage(contentsOfFile: path) で画像ファイルから UIImage オブジェクトを生成して imageData に代入しています。

6 行目で、imageData が nil でなければ、imageView.image に imageData を代入して、UIImageView に読み込んだ画像を表示しています。


これで、Swift で画像データをユーザーの Document Directory の保存し、その画像ファイルを読み込んで UIImageView に表示するコードが書けました。

できあがった ViewController.swift を載せておきます。今回追加したのは 34 ~ 70 行目です。

info.plist の設定など詳しくは「カメラで写真を撮る方法」をご覧ください。

import UIKit

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var imageView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func takePhotoTapped(_ sender: Any) {
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            let imagePicker = UIImagePickerController()
            imagePicker.sourceType = .camera
            imagePicker.delegate = self
            self.present(imagePicker, animated: true, completion: nil)
        }
        else {
            print("Camera not available.")
        }
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true)

        guard let image = info[.originalImage] as? UIImage else {
            print("Image not found.")
            return
        }

        imageView.image = image
    }
    
    func getFileURL(fileName: String) -> URL {
        let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        return docDir.appendingPathComponent(fileName)
    }
    
    @IBAction func savePhotoTapped(_ sender: Any) {
        guard let imageData = imageView.image?.jpegData(compressionQuality: 1.0) else {
            return
        }
    
        do {
            try imageData.write(to: getFileURL(fileName: "IMG12345.jpg"))
            print("Image saved.")
        } catch {
            print("Failed to save the image:", error)
        }
    }
    
    @IBAction func clearPhotoTapped(_ sender: Any) {
        imageView.image = nil
    }
    
    @IBAction func loadPhotoTapped(_ sender: Any) {
        let path = getFileURL(fileName: "IMG12345.jpg").path

        if FileManager.default.fileExists(atPath: path) {
            if let imageData = UIImage(contentsOfFile: path) {
                imageView.image = imageData
            }
            else {
                print("Failed to load the image.")
            }
        }
        else {
            print("Image file not found.")
        }
    }
}

iOS アプリを iPhone にインストールしてテストする

写真を撮る箇所がシミュレーターでできないので、iPhone にインストールしてテストします。

作った iOS アプリを iPhone にインストールする方法がわからない方は「Xcode からアプリを iPhone にインストールして実行する方法」をご覧ください。


iPhone を指定してこのアプリを実行すると、以下のような画面が表示されるので、Take Photo ボタンをタップします。

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 3


インストールして初回の起動時はカメラの利用許可を求めるダイアログが表示されるので、OK をタップします。

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 4


カメラが起動するので、写真を撮ります。

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 9


この写真でよければ、Use Photo をタップします。撮り直したい時は Retake をタップして撮り直してください。

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 5


Use Photo をタップすると、カメラが閉じ、元の画面に戻って、撮った写真が画面に表示されるので、Save Photo をタップして写真を保存します。

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 6

Xcode の output window に Image saved. と表示されるはずです。


Clear Photo ボタンをタップして、Image View の画像を一旦削除します。

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 10


Load Photo ボタンをタップして、ユーザーの Document Directory に保存した画像をロードして表示します。

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 7

Swift - 画像ファイルをデバイスの Document Directory に保存・取得する方法 8

画像はデバイスに保存されているので、一旦アプリを落として再起動し、いきなり Load Photo をタップしても写真が表示されるはずです。


以上、Swift で画像ファイルをデバイスの Document Directory に保存・取得する方法をご説明しました。

© 2024 iOS 開発入門