在SwiftUI/AVPlayer中与NotificationCenter/Combine搏斗

在SwiftUI/AVPlayer中与NotificationCenter/Combine搏斗,swift,swiftui,avplayer,combine,notificationcenter,Swift,Swiftui,Avplayer,Combine,Notificationcenter,当物品播放完毕时,我试图暂停我的AVPlayer。使用SwiftUI执行此操作的最佳方法是什么?我不太了解通知,在哪里声明它们,等等。有没有一种方法可以使用Combine来实现这一点?示例代码将非常棒!先谢谢你 更新: 在下面答案的帮助下,我成功地创建了一个类,该类接受AVPlayer并在项目结束时发布通知。您可以使用以下内容订阅通知: 类别: import Combine import AVFoundation class PlayerFinishedObserver { let

当物品播放完毕时,我试图暂停我的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()
        }
    }
}
订阅某些视图:

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

我为类似问题找到了一个解决方案:

  • 我创建了
    AVPlayer
    的新子类
  • 将观察者添加到当前项目
  • 覆盖func
    observeValue
    ,当玩家到达结束时间时为当前物品添加观察者 以下是简化的示例:

    为播放器导入AVKit//
    导入Combine//以观察并添加为环境对象
    末级音频播放器:AVPlayer,ObservieObject{
    var songDidEnd=PassthroughSubject()//您可以在某些视图中与.onReceive函数一起使用它
    重写init(){
    super.init()
    registerObserves()
    }
    专用函数注册表观测值(){
    addObserver(self,forKeyPath:“currentItem”,选项:[.new],上下文:nil)
    //使用示例
    }
    重写func observeValue(forKeyPath keyPath:String?,对象的类别:Any?,更改:[NSKeyValueChangeKey:Any]?,上下文:UnasFemeutableRawPointer?){
    //播放器中的currentItem可能为零。我将observer添加到exist项中
    如果keyPath==“currentItem”,则让item=currentItem{
    NotificationCenter.default.addObserver(self,选择器:#选择器(playerIDfinishPlaying(:)),名称:NSNotification.name.AVPlayerItemDidPlayToEndTime,对象:item)
    //另一种方法,使用联合收割机
    var可取消:任何可取消?
    Cancelable=NotificationCenter.default.publisher(用于:.AVPlayerItemDidPlayToEndTime,对象:item)。接收{[weak self]\uIn
    self?.songdiden.send()
    可取消?.cancel()
    }
    }
    //其他观察员
    }
    @objc专用func播放器IDfinishPlaying(uuu通知:通知){
    playNextSong()//我的实现,在这里您可以写:“self.pause()”
    }
    }
    
    更新:使用
    .onReceive
    的简单示例(请注意,我在编写时没有使用/Xcode,因此可能会有错误):

    struct ContentView:View{
    @EnvironmentObject var audioPlayer:audioPlayer
    @国家机密var someText:String=“正在播放歌曲”
    var body:一些观点{
    文本(someText)
    .onReceive(self.audioPlayer.songdiden){//也许您需要在这里输入“uu”
    self.handleSongDidEnd()
    }
    }
    私有函数handleSongDidEnd(){
    打印(“歌曲结束了”)
    动画片{
    someText=“歌曲暂停”
    }
    }
    }
    
    关于
    AVPlayer
    组合:您可以查看我的,在那里您将看到一些观察播放时间的方法以及使用
    SwiftUI中的滑块回放时间的功能

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

    class SceneDelegate:UIResponder,UIWindowSceneDelegate{
    //其他工作人员
    func场景(场景:UIScene,willConnectTo会话:UISceneSession,选项connectionOptions:UIScene.connectionOptions){
    让homeView=ContentView()
    .environmentObject(AudioPlayer())
    //SceneDelegate的其他工作人员
    }
    }
    
    非常感谢!我很快就会试试的。你知道有没有办法使用更像这样的东西?NotificationCenter.default.publisher(用于:.AVPlayerItemDidPlayToEndTime),然后使用。(onReceive:)响应?我想知道是否有办法避免@objc。我的很多AVPlayer函数都在我的SwiftUI视图中,它不允许我在那里使用objc,因为它是一个结构。或者我应该将函数移到AudioPlayer is class中吗?@StormTrooper您可以在
    @objc
    函数中更改一些
    发布者
    ,例如
    songdiden.send()
    (您需要创建
    让songdiden=PassthroughSubject()
    )。因此,您可以像往常一样使用
    .onReceive
    。关于
    NotificationCenter.default.publisher(用于:.AVPlayerItemDidPlayToEndTime)
    -很有趣,也许我会尝试使用它。但是不,我不知道这样做,所以我不能说,在这个重要时刻它是否有效,谢谢。我会把它弄得一团糟,然后再打给你。非常感谢您的帮助。@StormTrooper,您的想法是对的,您可以编写以下内容:
    NotificationCenter.default.publisher(for:.AVPlayerItemDidPlayToEndTime,object:item)
    而不是我的变体。谢谢你的想法)@StormTrooper我更新了代码片段,下面是你想法的例子。我没有测试,但你可以试试。看来会奏效的
    .onReceive(finishedObserver.publisher) {
                    print("Gotcha!")
                }