'#selector' относится к методу, который не предоставляется Objective-C

105

Новый Xcode 7.3, передающий параметр через addTarget, обычно у меня работает, но в этом случае он выдает ошибку в заголовке. Любые идеи? Выдает другое, когда я пытаюсь изменить его на @objc

Спасибо!

cell.commentButton.addTarget(self, action: #selector(FeedViewController.didTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)

Селектор, который он вызывает

func didTapCommentButton(post: Post) {
}
Echizzle
источник
3
Как выглядит строка объявления класса FeedViewController? Как объявляется didTapCommentButton? Какую ошибку вы получаете при добавлении @objc?
vacawama
1
Обновление, я отредактировал свой пост. Я сейчас далеко от компьютера, на котором он включен, поэтому я забыл точное сообщение об ошибке, но это была одна из тех ситуаций, когда XCode говорит мне добавить его, а затем выдает ошибку по своему усмотрению.
Echizzle
2
Ваш класс объявляет @objcили является его подклассом NSObject?
NRitH
2
Можете попробовать убрать скобки? Это необычно, учитывая, что вы не должны вызывать функцию в селекторе.
DanielEdrisian
Это решило мою проблему за секунду http://stackoverflow.com/a/36963058/1685165
Darko

Ответы:

173

В моем случае функция селектора была private. Как только я удалил privateошибку, ошибка исчезла. То же самое и с fileprivate.

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

Шакед Саяг
источник
2
В дополнение к fileprivate.
hstdt
отличный улов @shaked
jbouaziz
@hstdt, так что если поставить, fileprivateрешится ли?
Хеманг
2
@Hemang, нет, @hstdt означает , что ни privateни fileprivateне будет работать
GOBE
Сделать func с динамическим более подходящим, чем удаление private / fileprivate.
Boon
57

Вам нужно использовать @objcатрибут on, didTapCommentButton(_:)чтобы использовать его #selector.

Вы говорите, что сделали это, но получили еще одну ошибку. Я предполагаю, что новая ошибка заключается в том, что Postтип ошибки не совместим с Objective-C. Вы можете предоставить метод Objective-C только в том случае, если все его типы аргументов и его возвращаемый тип совместимы с Objective-C.

Вы можете исправить это, создав Postподкласс NSObject, но это не имеет значения, потому что аргумент to didTapCommentButton(_:)в Postлюбом случае не будет . Аргументом функции действия является отправитель действия, и этим отправителем будет commentButton, предположительно, объект UIButton. Вы должны объявить didTapCommentButtonтак:

@objc func didTapCommentButton(sender: UIButton) {
    // ...
}

Затем вы столкнетесь с проблемой получения Postсоответствующей нажатой кнопки. Есть несколько способов получить его. Вот один.

Я так понимаю (поскольку ваш код говорит cell.commentButton), что вы настраиваете табличное представление (или представление коллекции). И поскольку ваша ячейка имеет нестандартное свойство с именем commentButton, я предполагаю, что это настраиваемый UITableViewCellподкласс. Итак, предположим, что ваша ячейка PostCellобъявлена ​​так:

class PostCell: UITableViewCell {
    @IBOutlet var commentButton: UIButton?
    var post: Post?

    // other stuff...
}

Затем вы можете пройти вверх по иерархии представлений с помощью кнопки, чтобы найти PostCellи получить сообщение из него:

@objc func didTapCommentButton(sender: UIButton) {
    var ancestor = sender.superview
    while ancestor != nil && !(ancestor! is PostCell) {
        ancestor = view.superview
    }
    guard let cell = ancestor as? PostCell,
        post = cell.post
        else { return }

    // Do something with post here
}
Роб Мэйофф
источник
Если я хочу использовать его с глобальной функцией? @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
TomSawyer
Вы не можете использовать его с глобальной функцией.
Роб Майофф 04
8

Попробуйте указать селектором на функцию-оболочку, которая, в свою очередь, вызывает функцию вашего делегата. Это сработало для меня.

cell.commentButton.addTarget(self, action: #selector(wrapperForDidTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)

-

func wrapperForDidTapCommentButton(post: Post) {
     FeedViewController.didTapCommentButton(post)
}
pfj
источник
1
Сработало у меня! все еще не уверен, зачем это нужно, но я возьму!
Пол Лен
0

Как вы знаете, в selector[About] сказано, что Objective-Cследует использовать среду выполнения. Объявления, помеченные как privateили fileprivateне представляемые среде выполнения Objective-C по умолчанию . Поэтому у вас есть два варианта:

  1. Отметьте свое заявление privateили [О]fileprivate@objc
  2. Используйте internal, public, openмодификатор доступа [О]
yoAlex5
источник