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

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

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

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Swift

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

Q&A

解決済

2回答

203閲覧

[Swift] realmを用いた画像の保存・表示

Kaguya_4869

総合スコア117

Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Swift

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

0グッド

0クリップ

投稿2024/08/26 02:02

編集2024/08/27 00:37

実現したいこと

現在realmを用いて画像の保存・表示を行いたいと考えています。
モデルの中身は以下です。

Swift

1import Foundation 2import RealmSwift 3 4class MyModel: Object { 5 @objc dynamic var imageURL: String = "" 6 @objc dynamic var id: String = UUID().uuidString 7 override static func primaryKey() -> String? { 8 return "id" 9 } 10} 11

発生している問題・分からないこと

画像の保存及び取得はできているのですが、imageViewに画像をpathから表示するときにnilになってしまい、imageViewに画像が表示されません。表示する際のimageView.imageがnilになっているので、filePath!というパス名の画像はない(UIImage(contentsOfFile: filePath!)がnilになっている)ために起きていると思うのですが、解決方法がわかりません。
お力添えをいただけますと幸いです。

該当のソースコード

Swift

1// 保存 2var documentDirectoryFileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] 3 let filePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] 4 5func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { 6 if results.count != 0 { 7 results[0].itemProvider.loadDataRepresentation(forTypeIdentifier: "public.image") { data, _ in 8 DispatchQueue.main.async { 9 if let imageData = data, let image = UIImage(data: imageData) { 10 self.imageView.image = image 11 12 let model = MyModel() 13 do { 14 self.saveImage() 15 try model.imageURL = self.documentDirectoryFileURL.absoluteString 16 print("successfully saved image!") 17 } catch { 18 print("Failed to save image") 19 } 20 try! self.realm.write({ 21 self.realm.add(model) 22 }) 23 print("model: ", model) 24 } 25 } 26 } 27 } 28 picker.dismiss(animated: true) 29 } 30 31 func createLocalDataFile() { 32 let fileName = "\(UUID().uuidString).png" 33 if documentDirectoryFileURL != nil { 34 let path = documentDirectoryFileURL.appendingPathComponent(fileName) 35 documentDirectoryFileURL = path 36 } 37 } 38 39 func saveImage() { 40 createLocalDataFile() 41 let pngImageData = imageView.image?.pngData() 42 do { 43 try pngImageData?.write(to: documentDirectoryFileURL) 44 } catch { 45 print("error") 46 } 47 }

Swift

1// 表示 2var itemList: Results<MyModel>! 3override func viewWillAppear(_ animated: Bool) { 4 super.viewWillAppear(animated) 5 itemList = realm.objects(MyModel.self) 6 print("itemList: ", itemList!) 7 if (itemList.count != 0) { 8 let fileURL = URL(string: itemList[0].imageURL) 9 print("fileURL: ", fileURL!) 10 do { 11 let data = try Data(contentsOf: fileURL!) 12 print("data: ", data) 13 let image = UIImage(data: data) 14 imageView.image = image 15 } catch let err { 16 print("Error: \(err.localizedDescription)") 17 } 18 } 19 }

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

画像を保存した時及び表示する際の出力結果は以下のようになりました。

// 保存時 successfully saved image! model: MyModel { imageURL = file:///....../37AC5833-DE4F-4321-8A87-3734F28C51B9/Documents/0D41ED77-C001-45DA-814D-D79F96358C5B.png; id = 6EC2C4AD-8657-45C6-BC41-9BE24AB7F268; }
// 表示 - Modelの中身 itemList: Results<MyModel> <0x7f9544413830> ( [0] MyModel { imageURL = file:///....../37AC5833-DE4F-4321-8A87-3734F28C51B9/Documents/0D41ED77-C001-45DA-814D-D79F96358C5B.png; id = 6EC2C4AD-8657-45C6-BC41-9BE24AB7F268; } ) // 表示 - URL fileURL: file:///.../37AC5833-DE4F-4321-8A87-3734F28C51B9/Documents/0D41ED77-C001-45DA-814D-D79F96358C5B.png

表示する際にコンソールに以下のように出力されました。

Error: The file “0D41ED77-C001-45DA-814D-D79F96358C5B.png” couldn’t be opened because there is no such file.

また、Finderから保存されている写真を探したところ、添付写真の場所にあったのですが、これは保存してあるURLと違うフォルダ名になっていましたので、これが原因かと思います。(添付写真で選択している部分のフォルダ名が違う)
該当部分のフォルダ名は実行するたびに変わってしまっているため、写真が指定されたパスに存在しないとなってしまっています。
イメージ説明

補足

参考にしたサイトは以下です。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2024/08/26 13:27

「上記の詳細・結果」の「表示」の方で、 URLやPathが「Documents/」で終わっているのが気になりました。 「該当のソースコード」に`documentDirectoryFileURL`が設定されるところが記載されていないと思うのですが、この項目にはディレクトリではなくファイルのパスが設定されているでしょうか?
Kaguya_4869

2024/08/27 00:24

ご指摘ありがとうございます。 imageURLにはURLを保存したいと考えています。 documentDirectoryFileURLは以下のように宣言しています。 var documentDirectoryFileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
guest

回答2

0

一か所変更してみました。
こちらいかがでしょうか?
imageURLがファイルパスになっていなかった点かとおもいます。

swift

1// 保存はこっち 2func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { 3 let widthSize = 200.0 4 let heightSize = 100.0 5 let imageViewBackground = UIImageView() 6 imageViewBackground.center = CGPoint(x: bgView.center.x, y: bgView.center.y) 7 imageViewBackground.bounds = CGRect(x: 0, y: 0, width: widthSize, height: heightSize) 8 imageViewBackground.accessibilityIdentifier = UUID().uuidString 9 10 let yearFormatter = DateFormatter() 11 yearFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "yyy", options: 0, locale: Locale(identifier: "jp_EN")) 12 let monthFormatter = DateFormatter() 13 monthFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "MM", options: 0, locale: Locale(identifier: "jp_EN")) 14 let dayFormatter = DateFormatter() 15 dayFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "dd", options: 0, locale: Locale(identifier: "jp_EN")) 16 let year = yearFormatter.string(from: Date()) 17 let month = monthFormatter.string(from: Date()) 18 let day = dayFormatter.string(from: Date()) 19 20 let imageModel = MyModel() 21 let realm = try! Realm() 22 do { 23 imageModel.imageURL = documentDirectoryFileURL.path // 修正: pathに変更 24 imageModel.imageX = imageViewBackground.center.x 25 imageModel.imageY = imageViewBackground.center.y 26 imageModel.imageWidth = widthSize 27 imageModel.imageHeight = heightSize 28 imageModel.date = "\(year).\(month).\(day)" 29 imageModel.id = imageViewBackground.accessibilityIdentifier! 30 } catch { 31 print("failed to save image.") 32 } 33 try! realm.write { realm.add(imageModel) } 34 print("imageModel: ", imageModel) 35 36 if results.count != 0 { 37 results[0].itemProvider.loadDataRepresentation(forTypeIdentifier: "public.image") { data, _ in 38 DispatchQueue.main.async { 39 imageViewBackground.image = UIImage(data: data!)! 40 self.bgView.insertSubview(imageViewBackground, belowSubview: self.dateLabel) 41 } 42 } 43 } 44 picker.dismiss(animated: true) 45} 46

swift

1// 表示はこっち 2var imageItemList: Results<MyModel>! 3override func viewWillAppear(_ animated: Bool) { 4 super.viewWillAppear(animated) 5 let yearFormatter = DateFormatter() 6 yearFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "yyy", options: 0, locale: Locale(identifier: "jp_EN")) 7 let monthFormatter = DateFormatter() 8 monthFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "MM", options: 0, locale: Locale(identifier: "jp_EN")) 9 let dayFormatter = DateFormatter() 10 dayFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "dd", options: 0, locale: Locale(identifier: "jp_EN")) 11 let year = yearFormatter.string(from: Date()) 12 let month = monthFormatter.string(from: Date()) 13 let day = dayFormatter.string(from: Date()) 14 yearLabel.text = "\(year)" 15 dateLabel.text = "\(month).\(day)" 16 17 // realm 18 let realm = try! Realm() 19 self.imageItemList = realm.objects(MyModel.self).filter("date == %@", "\(year).\(month).\(day)") 20 print(imageItemList!) 21 22 // ユーザーが指定したx, y座標、sizeの画像を表示する 23 for i in 0..<imageItemList.count { 24 let imageView = UIImageView() 25 imageView.frame.size = CGSize(width: imageItemList[i].imageWidth, height: imageItemList[i].imageHeight) 26 imageView.center = CGPoint(x: imageItemList[i].imageX, y: imageItemList[i].imageY) 27 28 let filePath = imageItemList[i].imageURL 29 print("filePath: ", filePath) 30 31 if FileManager.default.fileExists(atPath: filePath) { 32 if let image = UIImage(contentsOfFile: filePath) { 33 imageView.image = image 34 self.bgView.insertSubview(imageView, belowSubview: dateLabel) 35 } else { 36 print("Failed to load image from path: \(filePath)") 37 } 38 } else { 39 print("File does not exist at path: \(filePath)") 40 } 41 } 42} 43

投稿2024/08/26 03:25

Ripple_py

総合スコア66

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

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

Kaguya_4869

2024/08/26 04:04

ありがとうございます。 ご指摘いただいた点を修正してみたのですが、状況は変わらずimageViewに画像は表示されませんでした。
guest

0

自己解決

原因

実行時にアプリのサンドボックス環境が再生成されるため、保存された時のURLと実行環境下での"Application"の次の階層名が違ってしまっていることが原因でした。(質問文で選択したフォルダ部分の名称が毎回変わってしまっている)

解決方法

毎回ディレクトリのURLを検索し、realmには画像の名前だけを保存することで解決しました。

Swift

1// 保存 2 func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { 3 if results.count != 0 { 4 results[0].itemProvider.loadDataRepresentation(forTypeIdentifier: "public.image") { data, _ in 5 DispatchQueue.main.async { 6 if let imageData = data, let image = UIImage(data: imageData) { 7 self.imageView.image = image 8 let fileName = UUID().uuidString 9 guard let url = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(fileName).jpeg") else { return } 10 let data = image.jpegData(compressionQuality: 1.0) 11 do { 12 try data?.write(to: url) 13 } catch let err { 14 print(err.localizedDescription) 15 } 16 try! self.realm.write({ 17 let model = MyModel() 18 model.imageURL = "\(fileName).jpeg" //imageURLには画像の名前を保存 19 self.realm.add(model) 20 }) 21 } 22 } 23 } 24 } 25 picker.dismiss(animated: true) 26 }

Swift

1// 表示 2 override func viewWillAppear(_ animated: Bool) { 3 super.viewWillAppear(animated) 4 itemList = realm.objects(MyModel.self) 5 print("itemList: ", itemList!) 6 7 if itemList.count != 0 { 8 guard let url = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(itemList[0].imageURL) else { return } // 検索 9 do { 10 let readData = try Data(contentsOf: url) 11 let readImage = UIImage(data: readData) 12 imageView.image = readImage 13 } catch let error { 14 print(error) 15 } 16 } 17 } 18

参考にしたサイト

File Managerでデータを書き込む、読み出す、削除する

投稿2024/08/27 08:01

Kaguya_4869

総合スコア117

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問