'#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? Як оголошеноTapCommentButton? Яку помилку ви отримуєте, додаючи @objc?
vacawama

1
Оновлення, я редагував своє повідомлення. Я далеко від комп’ютера, він зараз увімкнений, тому я забуваю точне повідомлення про помилку, але це було однією з тих ситуацій, коли XCode каже мені додати його, а потім видає помилку за власним рішенням.
Ехіззл

2
Ваш клас заявляє @objc, чи це підклас NSObject?
NRitH

2
Чи можете ви спробувати видалити дужки? Це незвично, якщо ви не повинні викликати функцію в селекторі.
DanielEdrisian

Це вирішило мою проблему за секунду http://stackoverflow.com/a/36963058/1685165
Darko

Відповіді:


173

У моєму випадку функцією селектора була private. Як тільки я видалив privateпомилку, не було. Те саме стосується fileprivate.

У Swift 4
вам потрібно буде додати @objcдо декларації функції. До швидкості 4 це було неявно зроблено.


2
Окрім fileprivate.
hstdt

чудовий улов @shaked
jbouaziz

@hstdt, тож якщо ви встановите, fileprivateчи вирішиться це?
Хеман

2
@Hemang, ні, @hstdt означає, що ні працювати, privateні fileprivateпрацювати
Gobe

Зробити функцію динамічним більш підходящим, ніж видалення приватного / файлового приватного файлу.
Бун

57

Вам потрібно скористатися @objc атрибут , didTapCommentButton(_:)щоб використовувати його з#selector .

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

Ви можете це виправити, створивши Postпідклас NSObject, але це не має значення, оскільки аргумент доdidTapCommentButton(_:)Post все одно не буде . Аргументом функції дії є відправник дії, і цей відправник буде commentButton, імовірно, a 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

Ви не можете використовувати його з глобальною функцією.
грабувати майофф

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.