如何从独立 class (Swift 3) 获取通知
How to get Notification from standalone class (Swift 3)
我想在观察者在另一个 class 中收到通知后立即调用方法。问题是我不能从另一个调用一个 class,因为那时我会得到递归调用。
1) 带有播放器实例的控制器 class:
// PlayerController.swift
// player
import UIKit
import MediaPlayer
class NowPlayingController: NSObject {
var musicPlayer: MPMusicPlayerController {
if musicPlayer_Lazy == nil {
musicPlayer_Lazy = MPMusicPlayerController.systemMusicPlayer()
let center = NotificationCenter.default
center.addObserver(
self,
selector: #selector(self.playingItemDidChange),
name: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange,
object: musicPlayer_Lazy)
musicPlayer_Lazy!.beginGeneratingPlaybackNotifications()
}
return musicPlayer_Lazy!
}
//If song changes
func playingItemDidChange(notification: NSNotification) {
//somehow call updateSongInfo() method from 2nd class
}
//Get song metadata
func getSongData() -> (UIImage, String?, String?) {
let nowPlaying = musicPlayer.nowPlayingItem
//...some code
return (albumImage, songName, artistAlbum)
}
func updateProgressBar() -> (Int?, Float?){
let nowPlaying = musicPlayer.nowPlayingItem
var songDuration: Int?
var elapsedTime: Float?
songDuration = nowPlaying?.value(forProperty: MPMediaItemPropertyPlaybackDuration) as? Int
elapsedTime = Float(musicPlayer.currentPlaybackTime)
return(songDuration, elapsedTime)
}
}
2) 当玩家控制器收到通知时应该更新的视图控制器
// MainViewController.swift
// player
import UIKit
class MainViewController: UIViewController {
let playerController = PlayerController()
@IBOutlet weak var albumView: UIImageView!
@IBOutlet weak var songLabel: UILabel!
@IBOutlet weak var artistAlbum: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//Start updating progress bar
Timer.scheduledTimer(timeInterval: 0.5,
target: self,
selector: #selector(MainViewController.updateProgressBar),
userInfo: nil,
repeats: true)
}
private func updateSongInfo(){
(albumView.image!, songLabel.text, artistAlbum.text) = playerController.getSongData()
}
private func updateProgressBar(){
(progressBar.maximumValue, progressBar.value) = playerController.playingItemProgress()
}
}
Swift3 的解决方案:
在 NowPlayingController 中:
let newSongNotifications = NSNotification(name:NSNotification.Name(rawValue: "updateSongNotification"), object: nil, userInfo: nil)
func playingItemDidChange(notification: NSNotification) {
NotificationCenter.default.post(newSongNotifications as Notification)
}
在其他控制器中:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.updateSongInfo), name: NSNotification.Name(rawValue: "updateSongNotification"), object: nil)
}
您可以使用委托方法来更新 MainViewController
您可以 post 在自定义对象中需要的地方发出通知:
let notification = NSNotification(name:"doSomethingNotification", object: nil, userInfo: nil)
NotificationCenter.defaultCenter.postNotification(notification)
然后在您想要执行某些操作以响应此通知的其他视图控制器中,您告诉它观察 viewDidLoad()
中的通知。你传入的选择器就是你想要在收到通知时执行的方法。
override func viewDidLoad(){
super.viewDidLoad()
NotificationCenter.addObserver(self, selector: #selector(self.doSomething), name: "doSomethingNotification", object: nil)
}
我想在观察者在另一个 class 中收到通知后立即调用方法。问题是我不能从另一个调用一个 class,因为那时我会得到递归调用。
1) 带有播放器实例的控制器 class:
// PlayerController.swift
// player
import UIKit
import MediaPlayer
class NowPlayingController: NSObject {
var musicPlayer: MPMusicPlayerController {
if musicPlayer_Lazy == nil {
musicPlayer_Lazy = MPMusicPlayerController.systemMusicPlayer()
let center = NotificationCenter.default
center.addObserver(
self,
selector: #selector(self.playingItemDidChange),
name: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange,
object: musicPlayer_Lazy)
musicPlayer_Lazy!.beginGeneratingPlaybackNotifications()
}
return musicPlayer_Lazy!
}
//If song changes
func playingItemDidChange(notification: NSNotification) {
//somehow call updateSongInfo() method from 2nd class
}
//Get song metadata
func getSongData() -> (UIImage, String?, String?) {
let nowPlaying = musicPlayer.nowPlayingItem
//...some code
return (albumImage, songName, artistAlbum)
}
func updateProgressBar() -> (Int?, Float?){
let nowPlaying = musicPlayer.nowPlayingItem
var songDuration: Int?
var elapsedTime: Float?
songDuration = nowPlaying?.value(forProperty: MPMediaItemPropertyPlaybackDuration) as? Int
elapsedTime = Float(musicPlayer.currentPlaybackTime)
return(songDuration, elapsedTime)
}
}
2) 当玩家控制器收到通知时应该更新的视图控制器
// MainViewController.swift
// player
import UIKit
class MainViewController: UIViewController {
let playerController = PlayerController()
@IBOutlet weak var albumView: UIImageView!
@IBOutlet weak var songLabel: UILabel!
@IBOutlet weak var artistAlbum: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//Start updating progress bar
Timer.scheduledTimer(timeInterval: 0.5,
target: self,
selector: #selector(MainViewController.updateProgressBar),
userInfo: nil,
repeats: true)
}
private func updateSongInfo(){
(albumView.image!, songLabel.text, artistAlbum.text) = playerController.getSongData()
}
private func updateProgressBar(){
(progressBar.maximumValue, progressBar.value) = playerController.playingItemProgress()
}
}
Swift3 的解决方案:
在 NowPlayingController 中:
let newSongNotifications = NSNotification(name:NSNotification.Name(rawValue: "updateSongNotification"), object: nil, userInfo: nil)
func playingItemDidChange(notification: NSNotification) {
NotificationCenter.default.post(newSongNotifications as Notification)
}
在其他控制器中:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.updateSongInfo), name: NSNotification.Name(rawValue: "updateSongNotification"), object: nil)
}
您可以使用委托方法来更新 MainViewController
您可以 post 在自定义对象中需要的地方发出通知:
let notification = NSNotification(name:"doSomethingNotification", object: nil, userInfo: nil)
NotificationCenter.defaultCenter.postNotification(notification)
然后在您想要执行某些操作以响应此通知的其他视图控制器中,您告诉它观察 viewDidLoad()
中的通知。你传入的选择器就是你想要在收到通知时执行的方法。
override func viewDidLoad(){
super.viewDidLoad()
NotificationCenter.addObserver(self, selector: #selector(self.doSomething), name: "doSomethingNotification", object: nil)
}