简体   繁体   中英

Updating UIProgressView via delegate method on AudioPlayer

I'm attempting to use CADisplayLink to update a UIProgressView . Here's CADisplayLink 's initialiation signature

Here's a summary of the relevant variables from MyAudioPlayer class.

protocol AudioPlayerDelegate: class {
    func updateSlider(sender: AudioPlayer)
}

class AudioPlayer: NSObject {
    // relevant vars
    var updater: CADisplayLink?
    weak var delegate: AudioPlayerDelegate?

    func play() {
        // some setup stuff

        updater = CADisplayLink(target: self, selector: #selector(delegate?.updateSlider(sender:)))

        // regular stuff to play an audio file
    }
}

When I initialize updater in the play() method, the compiler says, :

Argument of #selector refers to instance method updateSlider(sender:) that is no exposed to Objective-C.

Easy enough...add objc in front of func updateSlider(sender: AudioPlayer) , like so:

@objc func updateSlider(sender: AudioPlayer)

The compiler error goes away for a nanosecond, then the the line I just updated says:

@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes.

There are a few answers covering this topic , but I haven't found one that works.

I tried throwing updateSlider in an extension instead of in the protocol section, but I keep getting this ping pong of the compiler wanting to add @objc in front followed by wanting to remove it.

I also attempted to use an instance of the Timer class instead of the CADisplayLink class to do this, but I encounter the same issue.

Thank you for reading. I welcome your suggestions.

It could be fixed so :)

func play() {
    // some setup stuff

    updater = CADisplayLink(target: self, selector: #selector(updateSlider(sender:)))

    // regular stuff to play an audio file
}

func updateSlider(sender: AudioPlayer) {
    delegate?.updateSlider(sender: sender)
}

Dan got me over the finish line on this issue. Instead of adding @objc in front of just my delegate method, I needed to add @objc in front of the protocol declaration.

// First change
@objc protocol AudioPlayerDelegate: class {
    @objc func updateSlider(sender: AudioPlayer)
}

Further down in the AudioPlayer class...

// Delegate declaration
weak var delegate: AudioPlayerDelegate?

// Second Change
if let delegate = delegate {
    updater = CADisplayLink(target: delegate, selector: #selector(AudioPlayerDelegate.updateSlider(sender:)))
    updater?.preferredFramesPerSecond = 30
    updater?.add(to: RunLoop.current, forMode: .commonModes)
}

Lastly, when done with the updater , invalidate it and nil it out (most likely in whatever method you use to stop your AVAudioPlayer instance.

    updater?.invalidate()
    updater = nil

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM