Ошибка «нераспознанный селектор отправлен в экземпляр» в Objective-C

155

Я создал кнопку и добавил действие для нее, но как только она была вызвана, я получил эту ошибку:

-[NSCFDictionary numberButtonClick:]: unrecognized selector sent to instance
 0x3d03ac0 2010-03-16 22:23:58.811
 Money[8056:207] *** Terminating app
 due to uncaught exception
 'NSInvalidArgumentException', reason:'*** -[NSCFDictionary numberButtonClick:]:  unrecognized selector sent to instance 0x3d03ac0'

Это мой код:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        UIButton *numberButton = [UIButton buttonWithType:UIButtonTypeCustom];        
        numberButton.frame = CGRectMake(10, 435, 46, 38);
        [numberButton setImage:[UIImage imageNamed:@"one.png"] forState:UIControlStateNormal];
        [numberButton addTarget:self action:@selector(numberButtonClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview: numberButton]; 
    }
return self;
}

-(IBAction)numberButtonClick:(id)sender{
    NSLog(@"---");
}
Привет мир
источник
Возможный дубликат ошибки
Cœur

Ответы:

187

Похоже, вы не управляете контроллером представления памяти должным образом, и в какой-то момент он освобождается, что приводит numberButtonClicked:к отправке метода другому объекту, который теперь занимает память, которую контроллер представления ранее занимал ...

Убедитесь, что вы правильно удерживаете / отпускаете свой контроллер вида.

Jasarien
источник
105
Это очень проницательный диагноз из нескольких строк кода.
Майкл Моррисон
41
ОК, значит проблема обнаружена ... но "Убедитесь, что вы правильно удерживаете / отпускаете свой контроллер вида." это предложение, а не решение.
Алекс Грэй,
12
@alex серый, что? Правильное управление памятью на контроллере представления решило проблему ... Я не понимаю, как это не является решением?
Jasarien
28
верный. хотя это кажется «исправлением»… и я могу быть в меньшинстве (хотя мне все еще удается существовать), но связь между проблемой и решением не сразу очевидна. например, я сталкиваюсь, -[NSWindow end]: unrecognized selector sent to instance 0x100523e80 и хотя я осознаю сходство с ОП и даже, возможно, причину проблемы из вашего ответа, реализация исправления не сразу очевидна
Алекс Грей,
12
Это сразу очевидно. Ваше управление памятью NSWindow не правильно где-то на линии. Пройдите его жизненный цикл и исправьте его.
Jasarien
127

Для тех, кто попал сюда через Google, как я, что, вероятно, больше относится к Xcode 4.2 + / iOS 5+, чем к ARC. У меня была такая же ошибка " нераспознанный селектор отправлен на экземпляр ". В моем случае я настроил целевое действие UIButton на передачу себя в качестве параметра sender, но позже понял, что оно мне не нужно, и удалил это в коде. Итак, что-то вроде:

- (IBAction)buttonPressed:(UIButton *)sender {

Был изменен на:

- (IBAction)buttonPressed {

Щелчок правой кнопкой мыши на соответствующей кнопке UIB показал, что событие Touch Up Inside было связано с контроллером представления buttonPressed: метод. Удаление этого и переназначение модифицированного метода сработало.

LeonardChallis
источник
Это было очень полезно, хотя я думаю, что его собственный вопрос и ответ облегчили бы его поиск.
Кертис Inderwiesche
@LeonardChallis Как вы можете ссылаться на отправителя в buttonPressed, если он не передан в качестве параметра?
Закданс
8
Очень полезный ответ. Я просто столкнулся с этой проблемой, и ваше решение было совершенно правильным. Следил за классом Стэнфордского iOS на iTunesU, когда это произошло. Еще раз спасибо за ваш ответ!
Маршалл Алсуп
1
@ LeonardChallis Спасибо. Я добавил бесплатный ответ на ваш ответ.
1,21 гигаватт
1
Я только что боролся с подобной проблемой, удалил параметр отправителя из функции выбора, а затем задавался вопросом, как получить отправителя. В моем случае я получал ошибку, потому что забыл поставить двоеточие после обратного вызова селектора, что вызвало несоответствие вызывающей последовательности. С помощью двоеточия я могу сохранить аргумент отправителя.
74

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

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

Поэтому убедитесь, что ваши действия правильно настроены.

Крис К
источник
Это была моя проблема. Я переименовал функцию и изменил свой код, но не изменил соединение в xib-файле.
BFTrick
2
СПАСИБО! Оказалось, что у меня было три метода, которые я удалил, и которые все еще упоминались. Беспокоит меня неделю!
эрдехайсер
25

Хорошо, я должен скинуться здесь. ОП динамически создал кнопку . У меня была похожая проблема, и ответ (после нескольких часов охоты) настолько прост, что меня тошнило.

Когда используешь:

action:@selector(xxxButtonClick:)

or (as in my case)

action:NSSelectorFromString([[NSString alloc] initWithFormat:@"%@BtnTui:", name.lowercaseString])

Если вы поместите двоеточие в конце строки - оно передаст отправителя. Если вы не поместите двоеточие в конец строки, это не произойдет, и получатель получит ошибку, если ожидает ее. Легко пропустить двоеточие, если вы динамически создаете имя события.

Параметры кода получателя выглядят так:

- (void)doneBtnTui:(id)sender {
  NSLog(@"Done Button - with sender");
}
 or
- (void)doneBtnTui {
  NSLog(@"Done Button - no sender");
}

Как обычно, это всегда очевидный ответ, который пропускается.

Крейг Х.
источник
1
Огромное спасибо! Это была моя проблема (не ставить двоеточие ':' в конце имени селектора). Почему почти всегда самые глупые простые вещи заставляют нас, гиков, биться головой об стену в 3 часа ночи? Большое спасибо!
TWright
23

В моем случае функция не ожидала аргумента, но кнопка была настроена для отправки аргумента, вызвавшего ошибку. Чтобы это исправить, мне пришлось перепрограммировать обработчик событий.

Вот моя функция:

введите описание изображения здесь

Обратите внимание, что он не содержит аргументов.

Вот изображение моей конфигурации кнопок (щелкните ее правой кнопкой мыши, чтобы просмотреть):

введите описание изображения здесь

Обратите внимание, что есть 3 обработчика событий.

Чтобы это исправить, мне пришлось удалить каждый из элементов события, так как один из них отправлял ссылку на себя в функцию enterPressed. Чтобы удалить эти элементы, я нажимал на маленький значок x рядом с названием каждого элемента, пока элементы не были показаны.

введите описание изображения здесь

Далее мне пришлось заново подключить кнопку к событию. Для этого удерживайте нажатой клавишу «Control», а затем перетащите линию от кнопки к действию. Стоит сказать «Подключи действие». Примечание: мне пришлось перезапустить XCode, чтобы это работало по какой-то причине; в противном случае это только позволяет мне вставлять действия (или создать новое действие) выше или ниже функции.

введите описание изображения здесь

Теперь у вас должен быть один обработчик события, связанный с событием кнопки, который не передает аргументов:

введите описание изображения здесь

Этот ответ дополняет ответ @Leonard Challis, который вы также должны прочитать.

1,21 гигаватт
источник
14

Это также может произойти, если вы не установили «Класс» представления в конструкторе интерфейса.

user1658373
источник
Ах, спасибо! Это вызвало сбой моего приложения при переходе к следующему этапу, просто забыл установить класс контроллера.
Eichhörnchen
Зачем это нужно знать классу? Я пытаюсь использовать UITableViewSection в качестве UIView, и поэтому я получаю эту ошибку. Компилятор говорит, что UITableViewSection не существует, поэтому я полагаю, что его внутренний UIKit.
Ян Варбертон
13

В моем случае я использовал NSNotificationCenter и пытался использовать селектор, который не принимал аргументов, но добавлял двоеточие. Удаление двоеточия решило проблему.

При использовании имени селектора не используйте завершающий двоеточие, если нет аргументов. Если есть один аргумент, используйте один конечный двоеточие. Если существует более одного аргумента, вы должны назвать их вместе с завершающим двоеточием для каждого аргумента.

Смотрите ответ Адама Розенфилда здесь: Селекторы в Objective-C?

Натан Гарабедян
источник
11

У меня была эта проблема с проектом Swift, где я создаю кнопки динамически. Код проблемы:

var trashBarButtonItem: UIBarButtonItem {
    return UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "newButtonClicked")
}

func newButtonClicked(barButtonItem: UIBarButtonItem) {
    NSLog("A bar button item on the default toolbar was clicked: \(barButtonItem).")
}

Решением было добавить двоеточие «:» после действия: например

var trashBarButtonItem: UIBarButtonItem {
        return UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "newButtonClicked:")
    }

    func newButtonClicked(barButtonItem: UIBarButtonItem) {
        NSLog("A bar button item on the default toolbar was clicked: \(barButtonItem).")
    }

Полный пример здесь: https://developer.apple.com/library/content/samplecode/UICatalog/Listings/Swift_UIKitCatalog_DefaultToolbarViewController_swift.html

FredL
источник
Сразу после
изучения
6

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

NSArray* array = [[NSArray alloc] init];
[(NSDictionary*)array objectForKey: key]; // array is not a dictionary, hence exception
devios1
источник
Это хороший совет - отказ от создания подкласса представления или объекта данных (например, из-за невозможности добавить имя подкласса) - это еще один способ, которым это происходит
Брэд М
4

У меня тоже была такая же проблема.

Я удалил свой uibutton в моей раскадровке и воссоздал его .. теперь все работает отлично.

Йохан Дахмани
источник
3

У меня была похожая проблема, но для меня решение было немного другим. В моем случае я использовал Category для расширения существующего класса (UIImage для некоторых возможностей изменения размера - см. Это руководство на случай, если вам интересно) и забыл добавить файл * .m в цель сборки. Глупая ошибка, но не всегда очевидная, когда случается, где искать. Я думал, что стоит поделиться ...

Мирко Ян
источник
3

Это произошло с моим, потому что случайно стерли «@IBAction func ...» внутри моего кода класса UIViewcontroller, поэтому в раскадровке был создан Reference Outlet, но во время выполнения была какая-то функция для его обработки.

Решение состояло в том, чтобы удалить ссылку Outlet внутри инспектора свойств, а затем заново создать ее, перетаскивая ее с помощью клавиши команды в код класса.

Надеюсь, поможет!

Гильермо
источник
Аналогично, это также случилось со мной, когда кнопка ссылалась на функцию, которой больше не существовало.
Джош Вольфф
2

Я думаю, что вы должны использовать void вместо IBAction в типе возврата. потому что вы определили кнопку программно.

Fa.Shapouri
источник
2

Другое возможное решение: Добавьте '-ObjC' к своим аргументам компоновщика.

Полное объяснение здесь: Objective-C категории в статической библиотеке

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

Русь Иган
источник
2

У меня была та же ошибка, и я обнаружил следующее:

Когда вы используете код

[self.refreshControl addTarget:self action:@selector(yourRefreshMethod:) forControlEvents:UIControlEventValueChanged];

Вы можете подумать, что он ищет селектор:

- (void)yourRefreshMethod{
    (your code here)
}

Но это на самом деле ищет селектор:

- (void)yourRefreshMethod:(id)sender{
    (your code here)
}

Этот селектор не существует, поэтому вы получите сбой.

Вы можете изменить селектор, чтобы получить (id) отправителя, чтобы устранить ошибку.

Но что, если у вас есть другие функции, которые вызывают функцию обновления без предоставления отправителя? Вам нужна одна функция, которая работает для обоих. Простое решение - добавить еще одну функцию:

- (void)yourRefreshMethodWithSender:(id)sender{
    [self yourRefreshMethod];
}

А затем измените код обновления выпадающего меню, чтобы вместо этого вызывать этот селектор:

[self.refreshControl addTarget:self action:@selector(yourRefreshMethodWithSender:) forControlEvents:UIControlEventValueChanged];

Я также прохожу курс по Stanford для iOS на старом Mac, который не может быть обновлен до новейшей версии Mac OSX. Так что я все еще строю для iOS 6.1, и это решило проблему для меня.

Джозеф Прайд
источник
2

В моем случае я решил проблему через 2 часа:

У отправителя (элемента tabBar) не было ссылки . Так что это никуда не указывало.

Juste создайте ссылочную точку соответствующий вашей функции.

Надеюсь, это поможет вам, ребята.

Андре Д.С.
источник
Просто добавлю, в моем случае я забыл портировать IBActionна Swift. Поэтому он жаловался на то, что хотел вызвать эту функцию, но ее не удалось найти.
DevNebulae
1

В настоящее время я изучаю разработку под iOS и прохожу книгу «Начало разработки под iOS6» от aPress. Я получил ту же ошибку в главе 10: раскадровки.

Мне потребовалось два дня, чтобы понять это, но обнаружил, что я случайно установил тег ячейки TableView в 1, когда мне не следовало этого делать. Для всех, кто делает эту книгу и получает подобную ошибку, я надеюсь, что это поможет.

Я действительно надеюсь, что будущие ошибки в моем коде будет легче найти! хахаха. Ошибка отладки никак не подтолкнула меня в правильном направлении, чтобы понять это (или, по крайней мере, я слишком новичок, чтобы понимать отладчик, смеется).

Шеннон Коул
источник
1

В моем случае я использовал UIWebView и передал NSString во втором параметре вместо NSURL. Поэтому я подозреваю, что неправильные типы классов, переданные в функции, могут вызвать эту ошибку.

jbaylina
источник
1

..А теперь моя

У меня была кнопка, связанная с методом, который обращался к параметру другой кнопки, и он работал отлично, НО, как только я попытался что-то сделать с самой кнопкой, у меня произошел сбой. Во время компиляции ошибки не отображались. Решение?

Мне не удалось связать кнопку с владельцем файла. Так что, если кто-нибудь здесь такой же глупый, как я, попробуйте это :)

user2875404
источник
1

Еще одно немного другое решение / случай.

Я использую Xamarin и MvvmCross, и я пытался привязать UIButton к ViewModel. Я подключил UIB-кнопку к розетке и TouchUpInside.

При связывании я использую только розетку:

set.Bind (somethingOutlet).For ("TouchUpInside").To(vm => vm.Something);

Все, что мне нужно было сделать, это удалить соединение action (TouchUpInside) в XCode, и это решило его.

PS Я полагаю, что все это основано на предыдущих ответах и, в частности, на @Chris Kaminski, но я надеюсь, что это кому-то поможет ...

Приветствия.

Yka
источник
1

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

Harshil.Chokshi
источник
1

Для меня это было оставшееся соединение, созданное в interfacebuilder bij ctrl-dragging. Имя разорванного соединения было в журнале ошибок

*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[NameOfYourApp.NameOfYourClass nameOfCorruptConnection:]:
unrecognized selector sent to instance 0x7f97a48bb000'

У меня было действие, связанное с кнопкой. Нажатие на кнопку привело к сбою приложения, поскольку в моем коде больше не было Outlet. Поиск имени в журнале привел меня к нему в раскадровке. Удалил его, и авария исчезла!

Том Бринккемпер
источник
0

Я отвечаю Леонарду Чаллису, так как я также принимал Stanford iOS класс C193P, как и пользователь "oli206"

«Завершение работы приложения из-за необработанного исключения« NSInvalidArgumentException », причина:»

Проблема заключалась в том, что у меня дважды была подключена кнопка «Ввод» на калькуляторе, и друг указал, что проверка кнопки в раскадровке показала, что 2 записи были в атрибутах «Подправить внутри», когда я щелкнул правой кнопкой мыши на кнопка «Ввод». Стирание одного из двух «Отправленных внутри» «Отправленных событий» решило проблему.

Это показало, что проблема вызвана (для класса видео C193P в пошаговом руководстве по калькулятору в задании 1) как 2 отправленных события, одно из которых вызвало исключение.

Peter_from_NYC
источник
У меня было 3 записи, некоторые как. :)
1.21 гигаватт
0

Это может произойти, если вы не назначаете ViewController для ViewControllerScene в InterfaceBuilder. Таким образом, ViewController.m не связан ни с одной сценой.

Винсент
источник
0

Другая действительно глупая причина этого состоит в том, что селектор определен в интерфейсе (.h), но не в реализации (.m) (опечатка)

JLA
источник
0

Еще одна причина / решение добавить в список. Это вызвано iOS6.0 (и / или плохим программированием). В более старых версиях селектор совпадал бы, если типы параметров совпадали, но в iOS 6.0 у меня возникали сбои в ранее работающем коде, где имя параметра было неправильным.

Я делал что-то вроде

[objectName methodName:@"somestring" lat:latValue lng:lngValue];

но в определении (и .h и .m) я имел

(viod) methodName:(NSString *) latitude:(double)latitude longitude:(double)longitude;

Это работало нормально на iOS5, но не на 6, даже на одной и той же сборке, развернутой на разных устройствах.

Во всяком случае, я не понимаю, почему компилятор не сказал мне этого - проблема единственная.

Тим Т
источник
0

Это также может произойти, если вы хотите установить свойство из ControllerA в открытое свойство внутри пользовательского класса ControllerB, и вы еще не установили «Пользовательский класс» внутри инспектора идентификации в раскадровках.

Франсиско Гутьеррес
источник
0

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

Я выделял разные xib для одного и того же UIVIewController, и даже после поиска везде я не мог найти, как это исправить. Затем я проверил свой AppDelegate, куда я звонил, initWithNibNameи вижу, что при копировании кода я изменил имя xib, но забыл изменить UIViewControllerкласс. Так что, если ни одно из решений не работает для вас, проверьте ваш initWithNibNameметод.

новичек
источник
0

Произошло со мной из-за противоречивых аргументов ограничения.

Алекс Бедро
источник