Обновление UIProgressView с помощью метода делегата на AudioPlayer

Я пытаюсь использовать CADisplayLink для обновления UIProgressView. Вот подпись инициализации CADisplayLink

Вот сводка соответствующих переменных из класса MyAudioPlayer.

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
    }
}

Когда я инициализирую updater в методе play(), компилятор говорит:

Аргумент #selector относится к методу экземпляра updateSlider(sender:), который не предоставляется Objective-C.

Достаточно просто ... добавьте objc перед func updateSlider(sender: AudioPlayer), например:

@objc func updateSlider(sender: AudioPlayer)

Ошибка компилятора исчезнет на наносекунду, затем в только что обновленной строке написано:

@objc можно использовать только с членами классов, протоколами @objc и конкретными расширениями классов.

Есть несколько ответов по этой теме, но я не нашел ни одного, который работал бы.

Я попытался добавить updateSlider в расширение, а не в раздел протокола, но я продолжаю получать этот пинг-понг о том, что компилятор хочет добавить @objc впереди, а затем удалить его.

Я также попытался использовать для этого экземпляр класса Timer вместо класса CADisplayLink, но столкнулся с той же проблемой.

Спасибо за чтение. Я приветствую ваши предложения.


person Adrian    schedule 30.05.2017    source источник
comment
Протокол должен быть помечен как @objc, а не метод внутри него. Кроме того, целью вашей отображаемой ссылки должно быть delegate, а для селектора - #selector(AudioPlayerDelegate.updateSlider(sender:)). Вам также, вероятно, следует развернуть свой делегат, прежде чем передавать его по ссылке отображения, но я не знаю, что на самом деле делает этот метод, если вы передадите его nil.   -  person dan    schedule 30.05.2017
comment
Вот и все. Я развернул делегата и инициализировал CADisplayLink, но объявление протокола objc привело меня к финишу. Я просто объявлял метод. Отправьте как ответ, чтобы потребовать свои 25. :)   -  person Adrian    schedule 30.05.2017


Ответы (2)


Дэн подвел меня к финишу в этом вопросе. Вместо добавления @objc перед моим методом делегата мне нужно было добавить @objc перед объявлением протокола.

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

Далее в классе AudioPlayer ...

// 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)
}

Наконец, когда закончите с updater, сделайте его недействительным и обнулите (скорее всего, с помощью любого метода, который вы используете для остановки своего экземпляра AVAudioPlayer.

    updater?.invalidate()
    updater = nil
person Adrian    schedule 30.05.2017

Это можно было исправить так :)

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)
}
person Vasilii Muravev    schedule 30.05.2017