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

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回答

1829閲覧

NotificationCenterのイベント通知を保存する方法

Ytan

総合スコア39

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/27 15:36

現状と質問

現在ViewControllerから3つのSliderでNavigationControllerとTabBarControllrtのTabBarの背景を
RGB変更をNotificationを使い変更をSecondViewControllerに反映しています。

しかし、このままだと再ビルドで初期状態に戻ってしまうので保存をしたいのですが、
アプリの本体設定の保存はUserDefaultsで良い、よく使う。と見る事が多々あります。

NotificationではNameを持たせていますが、UserDefaultsでもforkeyを持たせるので
以下のコードでいうcolor定数に二つの通知、変更を持たせるのは不可能だと思うのですが、
それぞれのsetとpostを呼ぶタイミングは同じ気がするのでどうしたらよろしいのでしょうか?

試しにUserDefaultsのみでやるとエラーが出たので違う気がします。
UserDefaultsのコメントアウトしたところもコメントインして行っても保存はされませんでした。

import UIKit class ViewController: UIViewController { @IBOutlet weak var redSlider: UISlider! @IBOutlet weak var greenSlider: UISlider! @IBOutlet weak var blueSlider: UISlider! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. redSlider.value = 0.5 greenSlider.value = 0.5 blueSlider.value = 0.5 changeTabBackgroundColor(red: redSlider.value, green: greenSlider.value, blue: blueSlider.value) // isTranslucet == false だと色の変更が効かない tabBarController?.tabBar.isTranslucent = true // UITabBar の背景を入れ替える //UITabBar.appearance().backgroundImage = UIImage() tabBarController?.tabBar.backgroundImage = UIImage() } @IBAction func sliderValueChange(_ sender: UISlider) { changeTabBackgroundColor(red: redSlider.value, green: greenSlider.value, blue: blueSlider.value) changeNavigationBacgroundColor(red: redSlider.value, green: greenSlider.value, blue: blueSlider.value) let color = UIColor(red: CGFloat(redSlider.value), green: CGFloat(greenSlider.value), blue: CGFloat(blueSlider.value), alpha: 1.0) let userInfo = [ "color" : color ] //UserDefaults.standard.set(color, forKey: "backgroundColor") NotificationCenter.default.post(name: NSNotification.Name(rawValue: "colorChangeValue"), object: nil, userInfo: userInfo) } func changeTabBackgroundColor(red: Float, green: Float, blue: Float) { tabBarController?.tabBar.backgroundColor = UIColor(red: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: 1.0) } func changeNavigationBacgroundColor(red: Float, green: Float, blue: Float) { self.navigationController?.navigationBar.backgroundColor = UIColor(red: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: 1.0) } }
import UIKit class SecondViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "colorChangeValue"), object: nil, queue: nil) { [weak self] (notice) in if let color = notice.userInfo?["color"] as? UIColor { // self?.navigationController?.navigationBar.backgroundColor = color self?.navigationController?.navigationBar.backgroundColor = UserDefaults.standard.object(forKey: "backgroundColor") as! UIColor } } } }

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

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

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

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

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

TsukubaDepot

2020/09/27 21:26

StackOverflowでも指摘しましたが、マルチポストは一般的に許容されていません。 ただ、マルチポストせざるを得ない理由もあるかと思いますので、その場合には一言入れた方が適切かと思いますので、そのようにご協力いただければと思います。
Ytan

2020/09/29 08:40

すみませんどちらで質問しようかと思いまずStackOverflowで投稿したのですが、こちらに投稿しなおそうとしてましたが向こうを削除し忘れていました。 削除しておきます。
guest

回答1

0

ベストアンサー

NotificationではNameを持たせていますが、UserDefaultsでもforkeyを持たせるので
以下のコードでいうcolor定数に二つの通知、変更を持たせるのは不可能だと思うのですが、
それぞれのsetとpostを呼ぶタイミングは同じ気がするのでどうしたらよろしいのでしょうか?

NotificationCenter と UserDefaults はそれぞれ目的が違います。

ざっくりいうと、

  • UserDefaults はデータの永続化を行う目的で利用
  • NotifivationCenter は異なるオブジェクト間でデータを共有する目的で利用

します。

なので、今回の目的であれば、

  • スライダで変更したデータは UserDefaults に保存し、次回以降の起動時に参照できるようにする
  • スライダで変更したデータは NotificationCenter を使い、異なる ViewController にメッセージを送り、受け取り先で動的に変更する

というコードを書く必要があるかと思います。

ということで、サンプルを作ってみました。

動的に変更されていることが分かりやすくなるように、あえて ViewController 内部に Containver View を作り、その中に Navigation Controller 配下の View Controller を配置することで、メインの View Controller に設置したスライダで調節した色が Container View 内部に配置した View Controller の navigation Bar の色にも反映されていることがわかるようにしてあります。

イメージ説明

とりあえず、関係するコードを掲載しますが、より確実に動作を確認するためには、github からサンプルコード一式をダウンロード(clone)し、実行されることをお勧めします。

  • [tsukubadepot /

teratail-294515_ObserverPattern ](https://github.com/tsukubadepot/teratail-294515_ObserverPattern)

###View Controller

Swift

1import UIKit 2 3class ViewController: UIViewController { 4 5 @IBOutlet weak var redSlider: UISlider! 6 @IBOutlet weak var greenSlider: UISlider! 7 @IBOutlet weak var blueSlider: UISlider! 8 9 @IBOutlet weak var containverView: UIView! 10 11 private let savedKey = "TabBarColor" 12 13 override func viewDidLoad() { 14 super.viewDidLoad() 15 // Do any additional setup after loading the view. 16 } 17 18 // MARK: - *** Notification Center 通知のタイミングもあり、ここでは viewDidAppear(_:)で実行している 19 override func viewDidAppear(_ animated: Bool) { 20 super.viewDidAppear(animated) 21 22 // MARK: 既に色情報が保存されていれば、それを読み込む。 23 if let savedColor = UserDefaults.standard.array(forKey: "TabBarColor") as? [Float] { 24 redSlider.value = savedColor[0] 25 greenSlider.value = savedColor[1] 26 blueSlider.value = savedColor[2] 27 } else { 28 redSlider.value = 0.5 29 greenSlider.value = 0.5 30 blueSlider.value = 0.5 31 } 32 33 changeTabBackgroundColor(red: redSlider.value, green: greenSlider.value, blue: blueSlider.value) 34 35 // isTranslucet == false だと色の変更が効かない 36 tabBarController?.tabBar.isTranslucent = true 37 38 // UITabBar の背景を入れ替える 39 tabBarController?.tabBar.backgroundImage = UIImage() 40 41 // MARK: Container View に枠線を入れる 42 containverView.layer.borderWidth = 2 43 containverView.layer.borderColor = UIColor.black.cgColor 44 } 45 46 @IBAction func sliderValueChange(_ sender: UISlider) { 47 changeTabBackgroundColor(red: redSlider.value, green: greenSlider.value, blue: blueSlider.value) 48 } 49 50 func changeTabBackgroundColor(red: Float, green: Float, blue: Float) { 51 52 let color = UIColor(red: CGFloat(redSlider.value), green: CGFloat(greenSlider.value), blue: CGFloat(blueSlider.value), alpha: 1.0) 53 tabBarController?.tabBar.backgroundColor = color 54 55 let userInfo = [ 56 "color" : color 57 ] 58 59 // MARK: NotificatonCenterで通知する 60 NotificationCenter.default.post(name: NSNotification.Name(rawValue: "colorChangeValue"), object: nil, userInfo: userInfo) 61 62 // UserDefaults で保存する 63 let savedColor = [redSlider.value, greenSlider.value, blueSlider.value] 64 UserDefaults.standard.setValue(savedColor, forKey: savedKey) 65 66 } 67}

###Second View Controller

Swift

1import UIKit 2 3class SecondViewController: UIViewController { 4 override func viewDidLoad() { 5 super.viewDidLoad() 6 // MARK: NavigationBarの背景を入れ替える(空の UIImage にする) 7 navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) 8 9 // MARK: "colorChangeValue" で紐付けっれた通知を受け取ったら、クロージャ内を実行する 10 NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "colorChangeValue"), object: nil, queue: nil) { 11 [weak self] (notice) in 12 13 if let color = notice.userInfo?["color"] as? UIColor { 14 self?.navigationController?.navigationBar.backgroundColor = color 15 16 } 17 } 18 19 // TODO: - 通知のタイミングによっては、ViewControllerからの通知が届かない可能性もあるので、初回のロード時だけは UserDefaults などからデータを得る方法も考えられる 20 21 } 22}

投稿2020/09/27 21:14

TsukubaDepot

総合スコア5086

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

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

Ytan

2020/09/29 09:01 編集

返信が遅くなってしまいすみません。 ViewControllerで変更した内容をUserDefaultsで保存する前にNotificationCenterでpostしているのはなぜですか? それぞれが違うkey,nameで動作をしていてもSecondViewControllerで毎回適応はされていますが、SecondViewControllerでUserDefaultsを呼ばれていないことから、それぞれは関係を持たず color,savedColor自体が保存されているわけでは無くredSlider.value, greenSlider.value, blueSlider.valueが保存されているためcolor,savedColorは両方とも保存されたデータということですか? また、ScondViewControllerはViewDidload時に適応されてないので UserDefaults などからデータを得る方法を考えます。
TsukubaDepot

2020/09/29 10:15

Stack Overflow で Notification Center を使ったメッセージの送受信について、丁寧な回答を受けていたにもかかわらず、その記事まで削除されたようですね。 そこでついた丁寧な回答をよく読み、わからなければリファレンスを引き、それでもわからなければ改めて質問すれば良いだけの話なのに、Ytanさんがやられたことは、その丁寧な回答をつけた方を蔑ろにする行為です。 少なくとも、「ViewControllerで変更した内容をUserDefaultsで保存する前にNotificationCenterでpostしているのはなぜですか?」という質問は、少なくとも Notification Center について調べれば多少なりとも情報が得られる話です。 ご自身では、どれだけ調べる努力をされたのでしょうか。 私は、この話からは手を引きたいと思います。
Ytan

2020/09/29 11:40

労力と親切心を無駄にしてしまい、すみませんとしか言いようがないです。反省します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問