カテゴリー: iOS

[Swift]アプリのフォアグラウンドに特定の処理を行う。

はじめに

こんにちは、鈴木です。
最近の端末ではタスクキルをしないと動きが重くなる事も減り、バックグラウンド→フォアグラウンドでアプリを起動し続ける事が多くなりました。
そのため重要なチェックなどはバックグラウンド→フォアグラウンドのタイミングでも行う実装を、備忘も兼ねて実装方法を投稿させていただきます。

今回の目標

バックフォアを行われた時に処理を設定する。
実装を行う処理として
・複数画面で通知を受ける事を想定しBaseとなるクラスを作成する
・何も処理を行わない
・ホーム画面を表示する
・バック後1分間でフォアグラウンドに戻る場合はそのままの画面を表示する
・一つ前の画面に戻す
上記の想定で作成していこうと思います。

画面構成

初期画面(FirstViewController)
第二画面(SecondViewController)
第三画面(ThirdViewController)
第四画面(FourthViewController)
おまけ (ModalViewController)

通知の設定

今回はNotificationを利用してフォアグラウンドとバックグラウンドを取得して行きたいと思います。
Notificationとは何らかのイベントをほかのクラスに送りたい時などにつかいます。
クラス間の親子関係などは特に意識せずに利用可能です。

//通知の送信
NotificationCenter.default.post(<#T##notification: Notification##Notification#>)
//通知の受信設定(通知を受信したらselecterの中身が呼ばれます)
NotificationCenter.default.addObserver(<#T##observer: Any##Any#>, selector: <#T##Selector#>, name: <#T##NSNotification.Name?#>, object: <#T##Any?#>)
//通知の受信削除
NotificationCenter.default.removeObserver(<#T##observer: NSObject##NSObject#>, forKeyPath: <#T##String#>)

通知の送信

通知の送信について
バックフォアを取得するだけであれば通知の送信はデフォルトで送信されているため不要です。
(急な仕様変更の時などを考えるのであれば下記と異なるKeyで通知を設定すれば可能です)
・フォアグラウンドになる時に送信されるKey
UIApplicationWillEnterForeground
・バックグラウンドになった時に送信されるKey
UIApplicationDidEnterBackground

通知の受信と削除-BaseController

今回はすべてのViewControllerで通知を受け取る設定を行います。
そのためBaseで下記のように実装しました。
・画面表示時に通知を受信設定を行う
・画面非表示時に受信非表示設定を行う
・このクラスでオーバーライドする用の関数を設定する

//
import UIKit

class BaseViewController : UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    //アプリが表示されるタイミングで呼ばれる。
    override func viewWillAppear(_ animated: Bool) {
        //通知を設定
        setNotificasion()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        //通知を解除
        removeNotification()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    //通知を設定
    func setNotificasion(){
        //通知設定フォアグラウンドになる前に呼ばれる通知を受け取る
        NotificationCenter.default.addObserver(self, selector: #selector(self.willEnterForeground(_:)), name: .UIApplicationWillEnterForeground, object: nil)
        //通知設定バックグラウンドになった時に呼ばれる通知を受け取る
        NotificationCenter.default.addObserver(self, selector: #selector(self.didEnterBackground(_:)), name: .UIApplicationDidEnterBackground, object: nil)
    }
    
    func removeNotification(){
        NotificationCenter.default.removeObserver(self)
    }
    //アプリがフォアグラウンドになる前に呼ばれるーオーバーライドして使用
    @objc func willEnterForeground(_ notification: Notification){
        print("Base:" + #function)
    }
    //アプリがバックグラウンドになった際に呼ばれるーオーバーライドして使用
    @objc func didEnterBackground(_ notification: Notification){
        print("Base:" + #function)
    }
}

それぞれの画面の設定

それでは各画面の設定を行って行きましょう。
BaseViewControllerが通知の受信と削除を行うように記述しました。
それぞれの画面で行うことは下記の通知がきたときの処理のオーバーライドのみです。

    //BaseViewControllerのオーバーライド フォアグラウンドになる
    override func willEnterForeground(_ notification: Notification){
    }

    //BaseViewControllerのオーバーライド バックグラウンドになった
    override func didEnterBackground(_ notification: Notification){
    }

初期画面(FirstViewController)

・初期画面で行いたい事
 何も処理を行わない
※ViewWillAppear(戻ってきた時にも呼ばれる)で表示した時に必ずチェックがある場合
 同じ内容をwillEnterForegroundをoverrideして記述してもいいかもしれません。

・コード
特になし(Base側のコードが呼ばれます)

第二画面(SecondViewController)

・第二画面で行いたい事
 ホーム画面を表示する
 NavigationControllerのpopToRootViewControllerを利用

・コード

    //BaseViewControllerのオーバーライド フォアグラウンドになる
    override func willEnterForeground(_ notification: Notification){
        //NaviGationControllerの取得
        if let navigationController = navigationController{
            //ホーム画面に戻る
            navigationController.popToRootViewController(animated: false)
        }
    }

第三画面(ThirdViewController

・第三画面で行いたい事
バックグラウンド後1分間でフォアグラウンドに戻る場合はそのままの画面を表示する
 バックグラウンド後に時刻を取得
 フォアグラウンド時に時刻を評価
 条件に一致しない場合は何もしない

・コード

    //バックグラウンドに移行時の時刻を取得
    var backgroundDate = Date()
    
    override func willEnterForeground(_ notification: Notification){
        if backgroundDate <= Date(timeIntervalSinceNow: -60),
            let navigationController = navigationController{
            //ホーム画面に戻る
            navigationController.popToRootViewController(animated: false)
        }
    }
    
    override func didEnterBackground(_ notification: Notification){
        backgroundDate = Date()
    }

第四画面(FourthViewController)

・第三画面で行いたい事
一つ前の画面に戻す
 navigationViewControllerのpopViewControllerを使用

・コード

    override func willEnterForeground(_ notification: Notification){
        if let navigationController = navigationController{
            //一つ前の画面に戻る
            navigationController.popViewController(animated: false)
        }
    }

おまけ (ModalViewController)

・おまけで行いたい事
 ホーム画面へ遷移する
 dismissでモーダルを閉じる
 NavigationControllerをKeyWindowから取得する
 NavigationControllerのpopToRootViewControllerを利用
・コード

    override func willEnterForeground(_ notification: Notification){
        self.dismiss(animated: false) {
            if let window = UIApplication.shared.keyWindow,
                let navigationController = window.rootViewController as? UINavigationController{
                navigationController.popToRootViewController(animated: false)
            }
        }
    }

さいごに

今回は画面遷移がメインで実装しました。
実際の使用パターンとしては
・画面表示時に通信のチェックを行う
・通信をキャンセルする
など通信関係がよく使われるのではないかと思います。

コードが多くなりがちなViewControllerを少しでも軽量化したいです。
最後までありがとうございます。

参考リンク

https://dev-reco.com/340
https://qiita.com/kijibato/items/a0b9b956f7a9a35dcf1d

suzuki

シェア
執筆者:
suzuki
タグ: Swift

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前