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

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

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

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

Q&A

解決済

1回答

1368閲覧

UserDefaultsまたはDocumentに画像をdataに変換して保存・読み込みする方法

progpen123

総合スコア3

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

0グッド

0クリップ

投稿2020/09/06 07:07

編集2020/09/06 07:12

前提・実現したいこと

画像をdataに変換してUserDefaultsに保存する
そしてセグエで繋げた次のViewでその画像をUserDefaultsから読み込んで表示できるようにしたい

UserDefaultsに画像データのような大きいのを保存するのはよくないみたいですが
Documentに保存するやり方も分からなかったので段階を踏んで学んでいくため
まずはUserDefaultsにて保存を目指していますイメージ説明

発生している問題・エラーメッセージ

ViewControllerでは
Value of optional type 'UIImage?' must be unwrapped to a value of type 'UIImage'

Coalesce using '??' to provide a default when the optional value contains 'nil'

Force-unwrap using '!' to abort execution if the optional value contains 'nil'

...

nextViewControllerでは
Cannot call value of non-function type 'UserDefaults'

###ソースコード(ViewController)

ViewController

1import UIKit 2 3class ViewController: UIViewController { 4 let defaults = UserDefaults.standard 5 let image = UIImage(named: "home.png") 6 7 @IBOutlet weak var imageview: UIImageView! 8 { 9 didSet 10 { 11 imageview.image = image 12 } 13 } 14 15 override func viewDidLoad() { 16 super.viewDidLoad() 17 // Do any additional setup after loading the view. 18 } 19 20 @IBAction func save(_ sender: Any) { 21 let pngImageData: Data? = UIImagePNGRepresentation(imageview.image) 22 defaults.set(pngImageData, forKey: "画像キー") 23 } 24}

ソースコード(nextViewController)

nextViewController

1import UIKit 2 3class nextViewController: UIViewController { 4 let defaults = UserDefaults.standard 5 6 @IBOutlet weak var nextimageview: UIImageView! 7 { 8 didSet 9 { 10 let nextimage = UIImage(data: defaults(forKey: "画像キー")) 11 nextimageview.image = nextimage 12 } 13 } 14 15 override func viewDidLoad() { 16 super.viewDidLoad() 17 18 // Do any additional setup after loading the view. 19 } 20}

補足情報(FW/ツールのバージョンなど)

Xcode 11.7

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

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

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

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

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

guest

回答1

0

ベストアンサー

インスタンス化した別の ViewController にデータを渡す目的だけで UserDefaults を使うのはあまり良い方法ではないかと思います(そのような例を紹介している書籍が多いのも事実ですが)。

インスタンス化した別の ViewController にデータを渡す方法はそれほど難しくはないので、この際理解してしまうのが良いかと思います。

下記の例では、UI部品(UIButtonなど)から Segue を引っ張っている場合の例ですが、 ViewController から引っ張っている場合でも、基本は同じとなります。

  • ViewController.swift

Swift

1import UIKit 2 3class ViewController: UIViewController { 4 let image = UIImage(named: "あつもり2.jpg") 5 6 @IBOutlet weak var imageview: UIImageView! 7 { 8 didSet 9 { 10 imageview.image = image 11 } 12 } 13 14 override func viewDidLoad() { 15 super.viewDidLoad() 16 // Do any additional setup after loading the view. 17 } 18 19 // Segue が実行される時に呼び出される 20 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 21 // Segue で呼び出されインスタンス化される ViewController が nextViewController クラスで、 22 // かつ imageView.image が nil でない場合 23 if let nextVC = segue.destination as? nextViewController, let image = imageview.image { 24 25 // PNG データを作る 26 let pngImageData = image.pngData() 27 28 // 次に表示する nextViewController クラスの pngImageData プロパティに値を代入する 29 nextVC.image = pngImageData 30 } 31 } 32}
  • nextViewController

Swift

1import UIKit 2 3// 流儀的にはクラス名の先頭は大文字にすべき 4// つまり、nextViewController -> NextViewController 5class nextViewController: UIViewController { 6 // ViewController から渡されるデータ。 7 var image: Data? 8 9 // 呼び出し順番の関係で、プロパティオブザーバは使わない 10 @IBOutlet weak var nextimageview: UIImageView! 11 12 override func viewDidLoad() { 13 super.viewDidLoad() 14 15 // もし、pngImage == nil であれば、「画像データがないよ」と表示し、viewDidLoad() を抜ける 16 guard let pngImage = image else { 17 print("画像データがないよ") 18 19 return 20 } 21 22 // PNG データを使って画像を表示 23 nextimageview.image = UIImage(data: pngImage) 24 } 25}

##追記

UserDefaults を使うとなると、まずはエラーが出ないようにする必要があります。
エラーのうち一つ目は、Data型を渡さなければいけないところにData?型を渡していることが原因です。

が、そもそも使おうとしているメソッドが古く廃止予定のメソッドなので、現行(Swift5)のメソッドに合わせて書き換える必要があります。

Swift

1import UIKit 2 3class ViewController: UIViewController { 4 let defaults = UserDefaults.standard 5 let image = UIImage(named: "あつもり2") 6 7 @IBOutlet weak var imageview: UIImageView! 8 { 9 didSet 10 { 11 imageview.image = image 12 } 13 } 14 15 override func viewDidLoad() { 16 super.viewDidLoad() 17 // Do any additional setup after loading the view. 18 } 19 20 @IBAction func save(_ sender: Any) { 21 // Value of optional type 'UIImage?' must be unwrapped to a value of type 'UIImage' 22 // let pngImageData: Data? = UIImagePNGRepresentation(imageview.image) 23 let pngImageData = imageview.image?.pngData() 24 defaults.set(pngImageData, forKey: "画像キー") 25 } 26}

一方、遷移先についてはこのような感じになります。
こちらは、取得するためのメソッド名が不足していることがエラーの原因です。

Swift

1import UIKit 2 3class nextViewController: UIViewController { 4 let defaults = UserDefaults.standard 5 6 @IBOutlet weak var nextimageview: UIImageView! 7 { 8 didSet 9 { 10 // Cannot call value of non-function type 'UserDefaults' 11 // let nextimage = UIImage(data: defaults(forKey: "画像キー")) 12 if let data = defaults.data(forKey: "画像キー") { 13 nextimageview.image = UIImage(data: data) 14 } 15 } 16 } 17 18 override func viewDidLoad() { 19 super.viewDidLoad() 20 21 // Do any additional setup after loading the view. 22 } 23}

しかし、実はこの方法ではうまく動きません。

というのは、ViewControllersave()が実行される前に、nextViewControllernextViewController に設定しているプロパティオブザーバが作用し、画像が保存されていないのにデータを読み込もうとしてしまうためです。

従って、ImageViewに画像を設定するのは、viewWillAppear()以降によびだされるメソッド内でおこなうことになります。

Swift

1import UIKit 2 3class nextViewController: UIViewController { 4 let defaults = UserDefaults.standard 5 6 @IBOutlet weak var nextimageview: UIImageView! 7 8 override func viewDidLoad() { 9 super.viewDidLoad() 10 // Do any additional setup after loading the view. 11 } 12 13 override func viewWillAppear(_ animated: Bool) { 14 super.viewWillAppear(animated) 15 if let data = defaults.data(forKey: "画像キー") { 16 nextimageview.image = UIImage(data: data) 17 } 18 } 19}

投稿2020/09/06 12:09

編集2020/09/06 13:10
TsukubaDepot

総合スコア5086

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

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

progpen123

2020/09/06 18:10

ご回答ありがとうございます。 今、少し時間が取れない状態でまだ試せていませんが後日やってみます! 解決した後ベストアンサーに選ばさせていただきます。
progpen123

2020/09/13 05:51

遅れて申し訳ございません。 先ほどUserDefaultsを使わない場合と使う場合の両方が無事動きました。 細かいところまで丁寧に解説いただきありがとうございました。 この知識を活かして引き続きアプリ開発をしていきたいと思います! ベストアンサーに選ばさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問