AVPlayer & SwiftUI Part 4: Better Player Observing

Chris Mash
3 min readMar 10, 2020

--

Update: Check out part 5 for SwiftUI’s own VideoPlayer view in iOS 14!

Note: video playback on the simulator seems to not show the video, just play the audio, so use a real device if necessary!

This blog is related to the SwiftUI video player that’s been progressing over part 1, part 2 and part 3 so you may benefit from reading those first!

For the record, I’ve been using Xcode 11.2.1 for this part of the series.

Where were we?

It’s been a while, but at the end of part 3 I wasn’t happy with how I was observing the player’s time and duration. My main concern was that it was the PlayerUIView that was doing the observation, but that class didn’t make any use of the time and duration of the player, so that wasn’t particularly good coding.

The problem I was having basically came down to the fact SwiftUI Views are structs and I needed a class to be able to observe the player. To be honest I’d all but forgotten about the issue until a chap called Andrew got in touch with me, trying to get some help in building upon the code presented in part 3. Andrew was having some trouble being able to switch the content the player was playing from a List whilst still keeping all the UI updating correctly for the new content.

When I looked into Andrew’s code I found the issue and also found that he wasn’t using the player for videos (like I’d been demonstrating), but audio.

Because Andrew wasn’t playing back videos the whole PlayerUIView was unnecessary as there was no AVPlayerLayer to be shown to the user, so the class was just left observing the player and really didn’t make sense to be a UIViewRepresentable.

So this drove me to have another look into how to better solve the player observing.

Better observing

What I found was another, shall we say, option. I’ll call it that as I’m not 100% sure it’s the best way, but it’s definitely an improvement in my eyes.

I tried quite a few avenues and came up against many frustrating dead ends (I’m sure we’ve all been there with SwiftUI when you try to step beyond the simple beginnings). What I ended up getting to work was creating a class to observe the player, which would then publish the changes into SwiftUI using Combine.

Here’s an example of a class that observes the player’s time changing:

We create the class with a player and add a ‘periodic time observer’ to fire every 0.5s that the player is playing. Whenever this happens we publish the time the player is currently at.

And that can be used in a SwiftUI View like this:

We’re subscribing to the publisher on the Text View (which feels weird and can actually be done on any View). Whenever a new time is published we update our local var, which then triggers the Text to be re-evaluated and updated.

The duration of the player’s item can be observed in a similar way, as can the player’s item changing. I’ve updated my GitHub repo for this series with an audio player alternative which uses these new observers and also shows how you can change the player’s item from a List.

--

--

Chris Mash

iOS developer since 2012, previously console games developer at Sony and Activision. Twitter: @CJMash