質問: view as! UISlider break } } // フォアグラウンド NotificationCenter.default.addObserver(self, selector: #selector(XXX.enterForeground(_:)), name: .UIApplicationWillEnterForeground, object: nil) // バックグラウンド NotificationCenter.default.addObserver(self, selector: #selector(XXX.enterBackground(_:)), name: .UIApplicationDidEnterBackground, object: nil) // 音量変更 NotificationCenter.default.addObserver(self, selector: #selector(XXX.volumeChange(_:)), name: NSNotification.Name("AVSystemController_SystemVolumeDidChangeNotification"), object: nil) } // フォアグラウンド通知 @objc func enterForeground(_ notification : Notification?) { if (self.isViewLoaded && (self.view.window != nil)) { // 登録 NotificationCenter.default.addObserver(self, selector: #selector(XXX.volumeChange(_:)), name: NSNotification.Name("AVSystemController_SystemVolumeDidChangeNotification"), object: nil) } } // バックグラウンド通知 @objc func enterBackground(_ notification : Notification?) { if (self.isViewLoaded && (self.view.window != nil)) { // 解除 NotificationCenter.default.removeObserver(self, name: NSNotification.Name("AVSystemController_SystemVolumeDidChangeNotification"), object: nil) } } // 音量変更 @objc private func volumeChange(_ notification: Notification?) { print("volumeChange") } ``` ### 試したこと・質問 ・色々試したところ、DispatchQueue.main.asyncAfterで遅延実行時に登録すると、"volumeChange"は表示されません。 以下参照。 ``` // フォアグラウンド通知 @objc func enterForeground(_ notification : Notification?) { if (self.isViewLoaded && (self.view.window != nil)) { // 遅延実行する必要あり? DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // 登録 NotificationCenter.default.addObserver(self, selector: #selector(XXX.volumeChange(_:)), name: NSNotification.Name("AVSystemController_SystemVolumeDidChangeNotification"), object: nil) } } } ``` 質問1. これは正しい処置なのでしょうか? 質問2. 何故、この処置で上手くいくのでしょうか? 質問3. 正しい処置を教えていただけないでしょうか? 以上、宜しくお願いします。
回答: 質問1. これは正しい処置なのでしょうか? すみません、これが正しいのか間違っているのかはわかりません。 質問2. 何故、この処置で上手くいくのでしょうか? アプリをバックグラウンドにしたあと、再度フォアグラウンドにしたとき [AppDelegate] applicationWillEnterForeground:(アプリを開きそうな時に呼ばれる) ↓ [AppDelegate] applicationDidBecomeActive:(アプリを開いた時に呼ばれる) このような順序で処理されていくようです。 参考資料↓ https://qiita.com/itoz/items/cac51cc75cee5b35b0f0 https://qiita.com/SoyaTakahashi/items/cc8f48af792c353cd9f3 ``` NotificationCenter.default.addObserver(self, selector: #selector(XXX.enterForeground(_:)), name: .UIApplicationWillEnterForeground, object: nil) ``` 「.UIApplicationWillEnterForeground」 → 「.UIApplicationDidBecomeActive」へ変更したら、問題なく処理がされました。 おそらく、アプリを開きそうな時に呼ぶとダメなのだと思います。 なぜダメかはわかりませんでした。 DispatchQueue.main.asyncAfterで遅延実行時に登録すると、アプリを開いた時に呼ばれるため期待通りの処理がなされるのだと思います。 質問3. 正しい処置を教えていただけないでしょうか? ``` NotificationCenter.default.addObserver(self, selector: #selector(XXX.enterForeground(_:)), name: .UIApplicationWillEnterForeground, object: nil) ``` .UIApplicationWillEnterForeground → .UIApplicationDidBecomeActiveへ修正し、 ``` // 音量変更 NotificationCenter.default.addObserver(self, selector: #selector(XXX.volumeChange(_:)), name: NSNotification.Name("AVSystemController_SystemVolumeDidChangeNotification"), object: nil) ``` をコメントアウトしてみてください。 はじめてアプリを起動するときもapplicationDidBecomeActiveは呼ばれているので不要かと思います。 アプリ起動 ↓ [AppDelegate] application:willFinishLaunchingWithOptions: ↓ [AppDelegate] application:didFinishLaunchingWithOptions: ↓ [ViewController] viewDidLoad ↓ [ViewController] viewWillAppear: ↓ [AppDelegate] applicationDidBecomeActive: ↓ [ViewController] viewDidAppear: ↓ iPadminiとiphoneSEでは期待通りの処理がなされました。