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


105

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

Спасибо!

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

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

func didTapCommentButton(post: Post) {
}

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

1
Сработало у меня! все еще не уверен, зачем это нужно, но я возьму!
Пол Лен

0

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

  1. Отметьте свое заявление privateили [О]fileprivate@objc
  2. Используйте internal, public, openмодификатор доступа [О]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.