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 methodupdateSlider(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.
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