【问题标题】:Getting notification when viewcontroller goes to background当视图控制器进入后台时收到通知
【发布时间】:2021-10-21 05:25:21
【问题描述】:

这可能很容易,但我真的不知道如何在视图进入后台并使用SceneDelegate 返回时获得通知。如果我有一个 viewController 通过返回主菜单或类似的东西进入后台,我如何通过 sceneWillResignActive 检测到它?

我发现 here 可以这样做:

let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.willResignActiveNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(appBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)

更具体地说,我有这个ViewController.swift:

import Foundation
import UIKit
import AVKit

class IntroViewController :  UIViewController {
    
    @IBOutlet weak var videoView: UIView!
    @IBOutlet weak var introLabel: UILabel!
    var player: AVPlayer?

    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        playVideo()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        NotificationCenter.default.removeObserver(self)
        if let player = player {
            player.pause()
        }
        player = nil
    }
    
    private func playVideo() {
        if player != nil {
            player!.play()
        } else {
            guard let path = Bundle.main.path(forResource: "intro_video", ofType:"mp4") else {
                debugPrint("intro.MP4 not found")
                return
            }
            player = AVPlayer(url: URL(fileURLWithPath: path))
            player!.actionAtItemEnd = .none
            let playerFrame = CGRect(x: 0, y: 0, width: videoView.frame.width, height: videoView.frame.height)
            
            NotificationCenter.default.addObserver(self,
                                                   selector: #selector(playerItemDidReachEnd(notification:)),
                                                   name: .AVPlayerItemDidPlayToEndTime,
                                                   object: player!.currentItem)
            
            let playerController = AVPlayerViewController()
            playerController.player = player
            playerController.videoGravity = .resizeAspectFill
            playerController.view.frame = playerFrame
            playerController.showsPlaybackControls = false
            addChild(playerController)
            videoView.addSubview(playerController.view)
            playerController.didMove(toParent: self)
            player!.play()
            player!.rate = 1.3
        }
    }
    
    @objc func playerItemDidReachEnd(notification: Notification) {
        let mainViewController = self.storyboard!.instantiateViewController(withIdentifier: "main_view_controller") as! MainViewController
        player!.pause()
        present(mainViewController, animated:true, completion:nil)
    }
    @IBAction func skipVideo(_ sender: Any) {
        if player != nil {
            player?.pause()
            player = nil
        }
        let mainViewController = self.storyboard!.instantiateViewController(withIdentifier: "main_view_controller") as! MainViewController
        present(mainViewController, animated:true, completion:nil)
    }
}

然后我们有SceneDelegate.swift:

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let _ = (scene as? UIWindowScene) else { return }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // Called as the scene is being released by the system.
        // This occurs shortly after the scene enters the background, or when its session is discarded.
        // Release any resources associated with this scene that can be re-created the next time the scene connects.
        // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // Called when the scene has moved from an inactive state to an active state.
        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // Called when the scene will move from an active state to an inactive state.
        // This may occur due to temporary interruptions (ex. an incoming phone call).
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // Called as the scene transitions from the foreground to the background.
        // Use this method to save data, release shared resources, and store enough scene-specific state information
        // to restore the scene back to its current state.
    }


}

我希望能够在用户离开应用时暂停并重新启动播放器。据我了解,为了启动播放器,应该以某种方式从sceneDidBecomeActive 调用某些东西。我不明白的是如何在sceneDidBecomeActive 中表明应该呈现的视图控制器是我想要的。

sceneDidBecomeActive(当然)每次我回到应用程序时都会被调用,无论我是从哪个ViewController 离开的。

在引用旧方法的链接中,似乎有一些通知程序可以分配一个 lambda。如果我在SceneDelegate 中有对ViewController 的引用,我必须以某种方式检查它是否应该变为活动状态?

我不觉得遵循我找到的关于SceneDelegates 的教程是一件非常简单的事情。他们主要谈论 Appdelegate 之间的差异以及您可以做什么,但从不谈论如何实际去做。

【问题讨论】:

  • 您能否定义一下“进入后台”对您意味着什么?当用户点击 iPhone 上的主页按钮或打开其他应用程序并返回时,应用程序作为一个整体进入后台并恢复,这也是 AppDelegateSceneDelegate 通知的内容。但是您所指定的问题似乎更像viewWillDisappearviewWillAppear,您可以查看ViewController 生命周期以获取更多详细信息stackoverflow.com/questions/5562938/…

标签: ios swift uiscenedelegate


【解决方案1】:

场景委托中的 resignActive、enterBackground 与应用委托中的相同。您可以做的是在 sceneDelegate 中引用您的视图控制器,并在其中一个场景委托方法运行时调用视图控制器的某些方法(您可以定义视图控制器将实现的协议)。

【讨论】:

  • 我如何知道哪个视图控制器将是活动的? sceneDidBecomeActive 总是在我回去的时候被调用。我有不止一个ViewController,如果我要回到那个,我只会调用特定的方法。
  • 你可以在post找到你想要的东西
猜你喜欢
  • 2014-01-12
  • 1970-01-01
  • 1970-01-01
  • 2013-03-09
  • 2018-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
相关资源
最近更新 更多