Swift 2 нераспознанный селектор в жесте касания

Недавно я начал обновлять свое приложение до Swift 2.0, но столкнулся с проблемой, которая имеет сотни разных ответов на SO, ни один из которых, похоже, не связан с моей проблемой.

(Это работало до обновления приложения до Swift 2.0), но я не смог найти никаких изменений, внесенных в распознаватели жестов?

Вот полная ошибка, которую я получаю:

[Stocks.SidePanelViewController proFormulaTapGesture]: нераспознанный селектор отправлен в экземпляр 0x14f06ae00

Завершение работы приложения из-за необработанного исключения «NSInvalidArgumentException», причина: «-[Stocks.SidePanelViewController proFormulaTapGesture]: нераспознанный селектор отправлен экземпляру 0x14f06ae00»

*** First throw call stack: (0x1830904d0 0x197afff9c 0x1830971ec 0x183094188 0x182f9920c 0x188c3c58c 0x188899b50 0x18872d104 0x188c3bc30 0x1886ed28c 0x1886eb3ac 0x18872b088 0x18872a5ec 0x1886fb908 0x1886f9fac 0x183047d6c 0x183047800 0x183045500 0x182f75280 0x18e0ec0cc 0x188762df8 0x100158184 0x1983428b8) libc++abi.dylib: terminating with uncaught exception of type NSException

Это простой жест касания. Но, похоже, он больше не распознает селектор.

Вот код, который я использую для настройки распознавателя:

let proFormulaTap = UITapGestureRecognizer()

proFormulaTap.addTarget(self, action:"proFormulaTapGesture")
proFormulaView.addGestureRecognizer(proFormulaTap)

Вот функция, которую я пытаюсь запустить:

func proFormulaTapGesture() throws {
        print("proFormulaTapGesture")
        selectView(proFormulaView)
        selectedMenuItem = 0
        Formula = 1
        menuTabBarController.selectedIndex = 0
        navigationController?.navigationBar.topItem!.title = "BASIC FORMULA"
        try (menuTabBarController.viewControllers as! [SuggestionsViewController])[0].loadSuggestions()
    }

Однако, поскольку он никогда не печатает proFormulaTapGesture в консоли. Я определенно думаю, что ошибка возникает до функции. Также предлагается ошибка с упоминанием селектора.

Очевидно, что после обновления до Swift 2.0 функция try/catch была добавлена, но ничего не изменилось в настройке tapGestureRecognizer.

Я попытался удалить броски и попробовать из функции, но проблема не устранена. Я также попытался сделать кнопку вместо распознавателя жестов касания. Но я все еще получаю ту же ошибку, предполагая, что это может быть проблема с селектором (функцией), а не с жестом/кнопкой касания. Однако все мои другие кнопки в моем приложении работают нормально?

Я также попытался переименовать селектор / функцию и распознаватель жестов касания. Все такой же.

Оригинальный код был запрограммирован на Swift, а не на Obj-C. Броски и попытки были добавлены во время преобразования кода Apple в Swift 2.0.

Любая помощь в том, почему это внезапно сломалось, будет принята с благодарностью.

Спасибо!


person Mark L    schedule 27.07.2015    source источник
comment
Вы только что попытались прокомментировать этот оператор try и удалить эти «броски» - просто чтобы проверить, не вызывает ли это проблему?   -  person Shripada    schedule 27.07.2015
comment
@nshebbar Я только что попробовал, все та же ошибка. Спасибо за предложение, хотя! Действительно ценю это!   -  person Mark L    schedule 27.07.2015
comment
Хм, хорошо, также попробуйте изменить имя функции.   -  person Shripada    schedule 27.07.2015
comment
@nshebbar Я только что обновил свой пост, добавив пару других попыток исправить это. Ага :(   -  person Mark L    schedule 27.07.2015
comment
Попробуйте полностью квалифицированную функцию, которая также принимает в качестве аргумента жестRecogniser: func proFormulaTapGesture(recognizer: UITapGestureRecognizer) throws . и для соответствия - proFormulaTap.addTarget(self, action:proFormulaTapGesture:)   -  person Shripada    schedule 27.07.2015
comment
@nshebbar Я попытался создать новую функцию, в которой была только печать. Все та же проблема.   -  person Mark L    schedule 27.07.2015
comment
@objc func proFormulaTapGesture() & Использование Swift с Cocoa и Objective-C.   -  person zrzka    schedule 27.07.2015
comment
@robertvojta Это не код Obj-C.   -  person Mark L    schedule 27.07.2015
comment
@MarkL, но UIKit это... UITapGestureRecognizer (Obj-C) вызывает ваш код Swift.   -  person zrzka    schedule 27.07.2015
comment
Забыл упомянуть, что @objc требуется, когда метод private. Они не отображаются автоматически в Objective-C.   -  person zrzka    schedule 27.07.2015


Ответы (1)


Проблема может заключаться в том, что UIKit не знает, как вызвать селектор, который throws, по крайней мере, в этом контексте.

Помните, что UIKit будет вызывать эту функцию в ответ на нажатие. Он не привык вызывать функцию, которая throws; очевидно, что throw должен изменить сигнатуру вызова метода, насколько это касается среды выполнения Objective-C. Кроме того, если ваша функция proFormulaTapGesture выдала ошибку, что UIKit сделал бы с этой ошибкой, даже если бы смог ее перехватить?

Я не знаю, где вы добавили do/try/catch. Но если это не было внутри вашей функции действия proFormulaTapGesture, я не понимаю, как это может быть актуально. Я считаю, что вам нужно будет реализовать обработку ошибок try/catch внутри proFormulaTapGesture, чтобы он эффективно проглатывал ошибку, чтобы proFormulaTapGesture не выбрасывало.

Я только что сам создал быстрый тестовый проект и обнаружил, что целевое действие throwing дает ту же ошибку «Неопознанный селектор», которую вы получили:

override func viewDidLoad() {
    super.viewDidLoad()

    self.tapper = NSClickGestureRecognizer(target: self, action: "didClick")
    self.view.addGestureRecognizer(self.tapper!)
}

func didClick() throws {
    print("did click")
}

2015-07-27 00:16:43.260 Test1[71047:54227175] -[Test1.ViewController didClick]: нераспознанный селектор отправлен экземпляру 0x6000000c5010

...

Я считаю, что вам нужно будет переработать свой код, чтобы обработать ошибку внутри вашей функции действия, чтобы она не выбрасывала - что-то вроде этого:

func proFormulaTapGesture() {
    print("proFormulaTapGesture")
    selectView(proFormulaView)
    selectedMenuItem = 0
    Formula = 1
    menuTabBarController.selectedIndex = 0
    navigationController?.navigationBar.topItem!.title = "BASIC FORMULA"
    do {
        try (menuTabBarController.viewControllers as! [SuggestionsViewController])[0].loadSuggestions()
    } catch {
        // Handle the error here somehow
    }
}

Если вы не можете обработать ошибку в proFormulaTapGesture, вам придется проявить больше изобретательности при передаче ее из функции (например, NSNotification и т. д.).


Чтобы было ясно, я создал новое приложение для iOS с одним представлением в Xcode 7 beta 4 и использовал этот точный код в качестве моего ViewController. Никаких других изменений. Приложение компилируется и отлично работает в симуляторе iOS.

@robertvojta также указывает, что если didTap ниже помечен private, @objc также требуется, чтобы избежать динамического сбоя диспетчеризации.

import UIKit

class ViewController: UIViewController {

    var tapper: UITapGestureRecognizer?

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tapper = UITapGestureRecognizer(target: self, action: "didTap")
        self.view.addGestureRecognizer(self.tapper!)
    }

    func didTap() {
        print("did Tap")
    }

}

(Обратите внимание, что я также тестировал проект OS X, который является кодом, который я использовал ранее в ответе).

person justinpawela    schedule 27.07.2015
comment
Наверное, я не уверен на 100%... Вы тестировали свой код? Вы должны использовать @objc, иначе вы все равно получите Неопознанный селектор.... - person zrzka; 27.07.2015
comment
Я попробую это, но, как упоминалось в посте, я уже пытался создать простую функцию, содержащую только печать, которая не выдавала. И это все еще не сработало. Но попробую еще раз убедиться :) Спасибо за ответ. - person Mark L; 27.07.2015
comment
Да, я все еще получаю ту же ошибку с вашим редактированием. - person Mark L; 27.07.2015
comment
Я понял. И этот ответ был правильным, несмотря на мою последнюю ошибку. После того, как я очистил проект, удалил старые файлы журнала и тому подобное. Перезапустил Xcode и снова запустил его, это сработало нормально. :) Большое спасибо! - person Mark L; 27.07.2015
comment
@ user2194039 удалил мой ответ. Чтобы сделать ваш ответ лучше, просто добавьте примечание о @objc, которое необходимо, когда метод является закрытым (по умолчанию они не доступны для ObjC). private func didTap() не будет работать без @objc. - person zrzka; 27.07.2015
comment
@robertvojta Спасибо, и я добавил еще немного кода, чтобы четко показать, что именно сработало. И действительно, как я упоминал ранее, @objc тоже было моей первой мыслью. Я использовал такой язык, как не уверен на 100%, потому что мой проверенный код работал, но у меня нет подтверждающей документации. - person justinpawela; 27.07.2015
comment
@robertvojta Я пересмотрел примечание о @objc на основе вашего комментария (я также проверил его и обнаружил, что он точен;)). Спасибо за немного информации о private и @objc; это объясняет некоторые вещи для меня. - person justinpawela; 27.07.2015
comment
@user2194039 безопасный подход, вероятно, состоит в том, чтобы пометить все эти динамические вещи с помощью @objc, даже если они автоматически отображаются в Objective-C. Не повредит, и если вы в будущем пометите его private, это не приведет к сбою. Также он действует как тег/комментарий — имейте в виду, что он будет использоваться из фреймворка Objective-C,... - person zrzka; 27.07.2015
comment
К вашему сведению. Цитата из примечаний к выпуску: Объявления, помеченные как частные, не отображаются в среде выполнения Objective-C, если они не аннотированы иным образом. Выходы IB, действия IB и управляемые свойства Core Data остаются доступными для Objective-C независимо от их уровня доступа. Если вам нужно, чтобы закрытый метод или свойство можно было вызывать из Objective-C (например, для более старого API, использующего обратный вызов на основе селектора), явно добавьте атрибут @objc в объявление. - person zrzka; 27.07.2015
comment
@robertvojta Согласен в 1000 раз, и теперь я знаю, почему. Спасибо! - person justinpawela; 27.07.2015