インスタンス化した別の ViewController にデータを渡す目的だけで UserDefaults を使うのはあまり良い方法ではないかと思います(そのような例を紹介している書籍が多いのも事実ですが)。
インスタンス化した別の ViewController にデータを渡す方法はそれほど難しくはないので、この際理解してしまうのが良いかと思います。
下記の例では、UI部品(UIButtonなど)から Segue を引っ張っている場合の例ですが、 ViewController から引っ張っている場合でも、基本は同じとなります。
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}
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}
しかし、実はこの方法ではうまく動きません。
というのは、ViewController
の save()
が実行される前に、nextViewController
の nextViewController
に設定しているプロパティオブザーバが作用し、画像が保存されていないのにデータを読み込もうとしてしまうためです。
従って、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 18:10
2020/09/13 05:51