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

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

新規登録して質問してみよう
ただいま回答率
85.50%
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回答

2332閲覧

Swift4 : 音量変更通知をバックグランド移行時に登録解除し、音量を変更後、フォアグランドで音量変更通知を登録しなおすと、通知が来てしまう

khayshi1985

総合スコア13

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グッド

1クリップ

投稿2018/01/10 05:39

編集2018/01/15 06:15

###前提・実現したいこと
・機種はipad(iphoneでは発生しない)
・viewDidLoad()内で、フォアグランド、バックグラウンド、音量変更の通知を登録する。
・バックグラウンド移行で音量変更通知を解除する。
・バックグラウンド時に、音量変更ボタンで音量を変更する。
・フォアグラウンド移行で音量変更通知を登録する。

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

エラーメッセージ ・下記ソースコードにおいて、フォアグランド移行のタイミングで "volumeChange"がバックグラウンドで音量を変更した回数だけ表示される。

###該当のソースコード

import UIKit import MediaPlayer class XXX { private var slider = UISlider() override func viewDidLoad() { super.viewDidLoad() let volumeView = MPVolumeView(frame : CGRect(x : 100, y : 100, width : 500, height : 10)) view.addSubview(volumeView) for view in volumeView.subviews { if (view.isKind(of: UISlider.self)) { // 音量変更をスライダーと結びつける self.slider = 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. 正しい処置を教えていただけないでしょうか?

以上、宜しくお願いします。

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

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

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

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

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

fuzzball

2018/01/12 10:29 編集

登録と削除が対になっているかどうか確認してみて下さい。
khayshi1985

2018/01/15 06:14

ご回答ありがとうございます。登録・削除はついになっています。確認したところ、iphoneでは発生しない現象ですので、追記いたします。
fuzzball

2018/01/15 07:28 編集

「対になっている」のは、実際の呼び出しを確認したのでしょうか?確認した方法を教えて下さい。
guest

回答1

0

ベストアンサー

質問1. これは正しい処置なのでしょうか?
すみません、これが正しいのか間違っているのかはわかりません。

質問2. 何故、この処置で上手くいくのでしょうか?
アプリをバックグラウンドにしたあと、再度フォアグラウンドにしたとき
[AppDelegate] applicationWillEnterForeground:(アプリを開きそうな時に呼ばれる)

[AppDelegate] applicationDidBecomeActive:(アプリを開いた時に呼ばれる)
このような順序で処理されていくようです。
参考資料↓
https://qiita.com/itoz/items/cac51cc75cee5b35b0f0
https://qiita.com/SoyaTakahashi/items/cc8f48af792c353cd9f3

swift

1NotificationCenter.default.addObserver(self, selector: #selector(XXX.enterForeground(_:)), 2 name: .UIApplicationWillEnterForeground, object: nil)

「.UIApplicationWillEnterForeground」 → 「.UIApplicationDidBecomeActive」へ変更したら、問題なく処理がされました。
おそらく、アプリを開きそうな時に呼ぶとダメなのだと思います。
なぜダメかはわかりませんでした。

DispatchQueue.main.asyncAfterで遅延実行時に登録すると、アプリを開いた時に呼ばれるため期待通りの処理がなされるのだと思います。

質問3. 正しい処置を教えていただけないでしょうか?

swift

1NotificationCenter.default.addObserver(self, selector: #selector(XXX.enterForeground(_:)), 2 name: .UIApplicationWillEnterForeground, object: nil)

.UIApplicationWillEnterForeground → .UIApplicationDidBecomeActiveへ修正し、

```swift

// 音量変更
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では期待通りの処理がなされました。

投稿2018/01/15 07:20

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問