gpt4 book ai didi

swift - 在 SwiftUI/AVPlayer 中与 NotificationCenter/Combine 作斗争

转载 作者:行者123 更新时间:2023-12-04 14:15:50 25 4
gpt4 key购买 nike

我试图在项目播放完毕后暂停我的 AVPlayer。使用 SwiftUI 执行此操作的最佳方法是什么?我不太了解通知,在哪里声明它们等。有没有办法为此使用 Combine?示例代码会很棒!提前谢谢你。

更新:

在下面答案的帮助下,我设法创建了一个类,该类采用 AVPlayer 并在项目结束时发布通知。您可以通过以下方式订阅通知:

类:

import Combine
import AVFoundation

class PlayerFinishedObserver {

let publisher = PassthroughSubject<Void, Never>()

init(player: AVPlayer) {
let item = player.currentItem

var cancellable: AnyCancellable?
cancellable = NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime, object: item).sink { [weak self] change in
self?.publisher.send()
print("Gotcha")
cancellable?.cancel()
}
}
}

添加到你的结构:

let finishedObserver: PlayerFinishedObserver

订阅一些 View :

.onReceive(finishedObserver.publisher) {
print("Gotcha!")
}

最佳答案

我找到了类似问题的解决方案:

  1. 我创建了 AVPlayer 的新子类;
  2. 将观察者添加到 currentItem
  3. 覆盖函数observeValue,当玩家到达结束时间时为当前项目添加观察者;

这是一个简化的例子:

import AVKit // for player
import Combine // for observing and adding as environmentObject

final class AudioPlayer: AVPlayer, ObservableObject {

var songDidEnd = PassthroughSubject<Void, Never>() // you can use it in some View with .onReceive function

override init() {
super.init()
registerObserves()
}

private func registerObserves() {
self.addObserver(self, forKeyPath: "currentItem", options: [.new], context: nil)
// example of using
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
// currentItem could be nil in the player. I add observer to exist item
if keyPath == "currentItem", let item = currentItem {
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(_:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: item)

// another way, using Combine
var cancellable: AnyCancellable?
cancellable = NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime, object: item).sink { [weak self] _ in
self?.songDidEnd.send()
cancellable?.cancel()
}
}
// other observers
}

@objc private func playerDidFinishPlaying(_ notification: Notification) {
playNextSong() // my implementation, here you can just write: "self.pause()"
}

}

更新:使用.onReceive 的简单示例(注意,我在没有使用 playground/Xcode 的情况下编写它,所以它可能会出错):

struct ContentView: View {

@EnvironmentObject var audioPlayer: AudioPlayer
@State private var someText: String = "song is playing"

var body: some View {
Text(someText)
.onReceive(self.audioPlayer.songDidEnd) { // maybe you need "_ in" here
self.handleSongDidEnd()
}
}

private func handleSongDidEnd() {
print("song did end")
withAnimation {
someText = "song paused"
}
}

}

关于CombineAVPlayer:可以看我的question ,您将在 SwiftUI 中看到一些观察播放时间的方法和使用 slider 倒带时间的功能。

我正在使用 AudioPlayer 的一个实例,控制播放/暂停功能或更改 currentItem(这意味着设置另一首歌曲),如下所示:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

// other staff
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let homeView = ContentView()
.environmentObject(AudioPlayer())

// other staff of SceneDelegate
}
}

关于swift - 在 SwiftUI/AVPlayer 中与 NotificationCenter/Combine 作斗争,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60480652/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com