Błąd „nierozpoznany selektor wysłany do instancji” w Objective-C

155

Utworzyłem przycisk i dodałem do niego akcję, ale jak tylko został wywołany, otrzymałem ten błąd:

-[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'

To jest mój kod:

- (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(@"---");
}
Witaj świecie
źródło

Odpowiedzi:

187

Wygląda na to, że nie zarządzasz prawidłowo pamięcią kontrolera widoku i jest on w pewnym momencie zwalniany - co powoduje, że numberButtonClicked:metoda jest wysyłana do innego obiektu, który teraz zajmuje pamięć, którą wcześniej zajmował kontroler widoku ...

Upewnij się, że prawidłowo zachowujesz / zwalniasz kontroler widoku.

Jasarien
źródło
105
To bardzo wnikliwa diagnoza na podstawie kilku linijek kodu.
Michael Morrison,
41
OK, więc zidentyfikowano problem ... ale „Upewnij się, że prawidłowo zachowujesz / zwalniasz kontroler widoku”. jest sugestią, a nie rozwiązaniem.
Alex Grey
12
@alex grey, co? Prawidłowe zarządzanie pamięcią na kontrolerze widoku rozwiązało problem ... Nie rozumiem, dlaczego to nie jest rozwiązanie?
Jasarien
28
poprawny. chociaż wydaje się, że jest to „poprawka”… i mogę być w mniejszości (chociaż nadal udaje mi się istnieć), ale związek między problemem a rozwiązaniem nie jest od razu oczywisty. na przykład napotykam -[NSWindow end]: unrecognized selector sent to instance 0x100523e80 i chociaż zdaję sobie sprawę z podobieństw do OP, a nawet prawdopodobnie przyczyny problemu z Twojej odpowiedzi, wdrożenie poprawki nie jest od razu oczywiste
Alex Gray
12
To jest od razu oczywiste. Twoje zarządzanie pamięcią NSWindow gdzieś nie jest poprawne. Przejdź przez jego cykl życia i popraw go.
Jasarien
127

Dla tych, którzy dostają się tutaj przez Google, tak jak ja, co prawdopodobnie dotyczy bardziej Xcode 4.2 + / iOS 5+, co z ARC. Wystąpił ten sam błąd „ nierozpoznany selektor wysłany do instancji ”. W moim przypadku miałem ustawioną akcję docelową UIButton, aby przekazywała się jako parametr nadawcy, ale później zdałem sobie sprawę, że nie jest to potrzebne i usunąłem to w kodzie. Więc coś takiego:

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

Został zmieniony na:

- (IBAction)buttonPressed {

Kliknięcie prawym przyciskiem myszy na dany przycisk UIButton pokazało, że zdarzenie Touch Up Inside było powiązane z metodą view controllers buttonPressed: method. Usunięcie tego i ponowne przypisanie go do zmodyfikowanej metody działało świetnie.

LeonardChallis
źródło
Było to bardzo pomocne, chociaż myślę, że jego własne pytanie i odpowiedź ułatwiłyby znalezienie.
Curtis Inderwiesche
@LeonardChallis Jak możesz odwołać się do nadawcy w buttonPressed, jeśli nie został on przekazany jako parametr?
zakany
8
Bardzo pomocna odpowiedź. Właśnie natknąłem się na ten konkretny problem i twoje rozwiązanie było dokładnie poprawne. Śledziłem lekcje Stanforda na iOS w iTunesU, kiedy to się stało. Jeszcze raz dziękuję za odpowiedź!
Marshall Alsup,
1
@LeonardChallis Thanks. Dodałem pochlebną odpowiedź do twojej odpowiedzi.
1,21 gigawata,
1
Po prostu zmagałem się z podobnym problemem, usunąłem parametr sender z funkcji selector, a potem zastanawiałem się, jak zdobyć nadawcę. W moim przypadku otrzymywałem błąd, ponieważ zapomniałem wstawić dwukropek po wywołaniu zwrotnym selektora, powodując w ten sposób niezgodność sekwencji wywołującej. Za pomocą dwukropka mogę zachować argument nadawcy.
74

To była najlepsza odpowiedź Google na ten problem, ale miałem inną przyczynę / skutek - pomyślałem, że dodam moje dwa centy na wypadek, gdyby inni natknęli się na ten problem.

Właśnie dziś rano miałem podobny problem. Odkryłem, że jeśli klikniesz prawym przyciskiem myszy element interfejsu użytkownika powodujący problem, możesz zobaczyć, jakie połączenia zostały utworzone. W moim przypadku miałem przycisk podłączony do dwóch akcji. Usunąłem akcje z menu prawego przycisku myszy i ponownie je połączyłem, a mój problem został naprawiony.

Więc upewnij się, że twoje działania są dobrze połączone.

Chris K
źródło
To był mój problem. Zmieniłem nazwę funkcji i zmieniłem kod, ale nie zmieniłem połączenia w pliku xib.
BFTrick,
2
DZIĘKUJĘ CI! Okazało się, że mam trzy metody, do których wciąż się odwoływałem. Przeszkadza mi przez tydzień!
erdekhayser
25

OK, muszę tu wejść. OP dynamicznie utworzył przycisk . Miałem podobny problem i odpowiedź (po godzinach polowania) jest tak prosta, że ​​zrobiło mi się niedobrze.

Podczas używania:

action:@selector(xxxButtonClick:)

or (as in my case)

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

Jeśli umieścisz dwukropek na końcu ciągu - przekaże on nadawcę. Jeśli nie umieścisz dwukropka na końcu łańcucha, to się nie stanie, a odbiorca otrzyma błąd, jeśli go oczekuje. Jeśli dynamicznie tworzysz nazwę wydarzenia, łatwo przeoczyć dwukropek.

Opcje kodu odbiornika wyglądają następująco:

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

Jak zwykle, zawsze pomija się oczywistą odpowiedź.

Craig H.
źródło
1
Dziękuję bardzo! To był mój problem (brak dwukropka „:” na końcu nazwy selektora). Jak to się dzieje, że prawie zawsze najgłupsze proste rzeczy sprawiają, że maniacy walą głowami o ścianę o 3 nad ranem? Naprawdę dziękuję!
TWright,
23

W moim przypadku funkcja nie oczekiwała argumentu, ale przycisk został skonfigurowany tak, aby wysyłał taki, który powoduje błąd. Aby to naprawić, musiałem ponownie połączyć program obsługi zdarzeń.

Oto moja funkcja:

wprowadź opis obrazu tutaj

Zauważ, że nie zawiera argumentów.

Oto obraz konfiguracji mojego przycisku (kliknij prawym przyciskiem myszy, aby go wyświetlić):

wprowadź opis obrazu tutaj

Zauważ, że istnieją 3 programy obsługi zdarzeń.

Aby to naprawić, musiałem usunąć wszystkie elementy zdarzenia, ponieważ jeden z nich wysyłał do siebie odniesienie do funkcji enterPressed. Aby usunąć te elementy, klikałem małą ikonę x obok nazwy każdego elementu, dopóki nie było żadnych elementów.

wprowadź opis obrazu tutaj

Następnie musiałem ponownie podłączyć przycisk do zdarzenia. Aby to zrobić, przytrzymaj klawisz Control, a następnie przeciągnij linię od przycisku do akcji. Powinien brzmieć „Połącz działanie”. Uwaga: musiałem zrestartować XCode, aby to zadziałało z jakiegoś powodu; w przeciwnym razie pozwala mi tylko wstawiać akcje (czyli tworzyć nowe akcje) powyżej lub poniżej funkcji.

wprowadź opis obrazu tutaj

Powinieneś teraz mieć pojedynczy program obsługi zdarzeń połączony ze zdarzeniem przycisku, które nie przekazuje żadnych argumentów:

wprowadź opis obrazu tutaj

Ta odpowiedź jest uzupełnieniem odpowiedzi @Leonard Challis, którą również powinieneś przeczytać.

1,21 gigawata
źródło
14

Może się to również zdarzyć, jeśli nie ustawisz „Klasy” widoku w programie do tworzenia interfejsów.

user1658373
źródło
Ach, dziękuję! To powodowało awarię mojej aplikacji na segue, po prostu zapomniałem ustawić klasę kontrolera.
Eichhörnchen
Dlaczego musi znać klasę? Próbuję użyć UITableViewSection jako UIView, więc otrzymuję ten błąd. Kompilator mówi, że UITableViewSection nie istnieje, więc zakładam, że jest to element wewnętrzny UIKit.
Ian Warburton,
13

W moim przypadku używałem NSNotificationCenter i próbowałem użyć selektora, który nie przyjmował żadnych argumentów, ale dodawał dwukropek. Usunięcie okrężnicy rozwiązało problem.

Używając nazwy selektora, nie używaj końcowego dwukropka, jeśli nie ma argumentów. Jeśli jest jeden argument, użyj jednego końcowego dwukropka. Jeśli istnieje więcej niż jeden argument, musisz nazwać je wraz z końcowym dwukropkiem dla każdego argumentu.

Zobacz odpowiedź Adama Rosenfielda tutaj: Selektory w celu C?

Nathan Garabedian
źródło
11

Miałem ten problem z projektem Swift, w którym dynamicznie tworzę przyciski. Kod problemu:

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

Rozwiązaniem było dodanie pełnego dwukropka „:” po akcji: np

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

Pełny przykład tutaj: https://developer.apple.com/library/content/samplecode/UICatalog/Listings/Swift_UIKitCatalog_DefaultToolbarViewController_swift.html

FredL
źródło
Zaraz po
przejrzeniu
6

Najbardziej oczywistą przyczyną tego (uwzględnioną w celu zapewnienia kompletności) jest nieprawidłowe rzutowanie wskaźnika i wywołanie metody o niewłaściwej klasie.

NSArray* array = [[NSArray alloc] init];
[(NSDictionary*)array objectForKey: key]; // array is not a dictionary, hence exception
devios1
źródło
To dobra wskazówka - brak podklasy widoku lub obiektu danych (np. Przez niepowodzenie dodania nazwy podklasy) to inny sposób
Brad M,
4

Miałem też ten sam problem.

Usunąłem mój uibutton w mojej planszy i odtworzyłem go… teraz wszystko działa dobrze.

Yohan Dahmani
źródło
3

Miałem podobny problem, ale dla mnie rozwiązanie było nieco inne. W moim przypadku użyłem kategorii, aby rozszerzyć istniejącą klasę (UIImage dla niektórych możliwości zmiany rozmiaru - zobacz ten poradnik, jeśli jesteś zainteresowany) i zapomniałem dodać plik * .m do celu kompilacji. Głupi błąd, ale nie zawsze oczywisty, gdy zdarza się, gdzie szukać. Pomyślałem, że warto się nim podzielić ...

Mirko Jahn
źródło
3

Stało się tak z moim, ponieważ przypadkowo usunąłem "@IBAction func ..." w kodzie mojej klasy UIViewcontroller, więc w Storyboard został utworzony Reference Outlet, ale w czasie wykonywania była jakakolwiek funkcja do przetwarzania.

Rozwiązaniem było usunięcie odniesienia Outlet wewnątrz inspektora właściwości, a następnie ponowne utworzenie go, przeciągając za pomocą klawisza polecenia do kodu klasy.

Mam nadzieję, że to pomoże!

Guillermo
źródło
Podobnie stało się ze mną, gdy przycisk odwoływał się do funkcji, która już nie istniała.
Josh Wolff,
2

Myślę, że w zwracanym typie należy użyć void zamiast IBAction. ponieważ zdefiniowałeś przycisk programowo.

Fa.Shapouri
źródło
2

Inne możliwe rozwiązanie: dodaj „-ObjC” do argumentów konsolidatora.

Pełne wyjaśnienie jest tutaj: Kategorie celu-C w bibliotece statycznej

Myślę, że sedno jest takie: jeśli kategoria jest zdefiniowana w bibliotece, z którą łączysz się statycznie, linker nie jest wystarczająco inteligentny, aby łączyć metody kategorii. Powyżej Flaga sprawia link łącznikową we wszystkich obiektywnych klas C i kategorii, a nie tylko te, których myśli, że musi na podstawie analizy źródło. (Nie krępuj się dostroić lub poprawić tę odpowiedź. Znam języki połączone, więc tutaj tylko papuguję).

Russ Egan
źródło
2

Miałem ten sam błąd i odkryłem, co następuje:

Kiedy używasz kodu

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

Możesz pomyśleć, że szuka selektora:

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

Ale tak naprawdę szuka selektora:

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

Ten selektor nie istnieje, więc pojawia się awaria.

Możesz zmienić selektor, aby odbierać (id) nadawcę, aby rozwiązać błąd.

Ale co, jeśli masz inne funkcje, które wywołują funkcję odświeżania bez podawania nadawcy? Potrzebujesz jednej funkcji, która będzie działać w obu przypadkach. Prostym rozwiązaniem jest dodanie kolejnej funkcji:

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

A następnie zmodyfikuj kod rozwijany odświeżania, aby zamiast tego wywoływał ten selektor:

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

Zajmuję się też kursem Stanford iOS na starszym Macu, którego nie można zaktualizować do najnowszej wersji Mac OSX. Więc nadal buduję dla iOS 6.1 i to rozwiązało problem.

Joseph Pride
źródło
2

W moim przypadku problem rozwiązałem po 2 godzinach:

Nadawca (element tabBar) nie miał żadnego punktu odniesienia . Więc nigdzie nie wskazywał.

Po prostu stwórz punkt odniesienia odpowiadający Twojej funkcji.

Mam nadzieję, że to może wam pomóc.

André DS
źródło
Dodam, że w moim przypadku zapomniałem przenieść IBActionna Swift. Narzekał więc, że chce wywołać tę funkcję, ale nie można jej znaleźć.
DevNebulae
1

Obecnie uczę się programowania na iOS i przeglądam książkę „Początek rozwoju iOS6” autorstwa aPress. Otrzymałem ten sam błąd w rozdziale 10: Storyboardy.

Zajęło mi to dwa dni, ale okazało się, że przypadkowo ustawiłem tag komórki TableView na 1, kiedy nie powinienem. Mam nadzieję, że dla każdego, kto robi tę książkę i otrzymuje podobny błąd, to pomoże.

Naprawdę mam nadzieję, że przyszłe błędy w moim kodzie będą łatwiejsze do znalezienia! hahaha. Błąd debugowania nie zrobił nic, aby popchnąć mnie we właściwym kierunku, aby to rozgryźć (a przynajmniej jestem zbyt nowy, aby zrozumieć debuger, lol).

Shannon Cole
źródło
1

W moim przypadku użyłem UIWebView i przekazałem NSString w drugim parametrze zamiast NSURL. Podejrzewam więc, że błędne typy klas przekazane do funkcji mogą powodować ten błąd.

jbaylina
źródło
1

..A teraz moja

Miałem przycisk powiązany z metodą, która uzyskiwała dostęp do parametru innego przycisku i działała świetnie, ALE gdy tylko próbowałem coś zrobić z samym przyciskiem, miałem awarię. Podczas kompilacji nie pojawił się żaden błąd. Rozwiązanie?

Nie udało mi się powiązać przycisku z właścicielem pliku. Więc jeśli ktoś tutaj jest tak głupi jak ja, spróbuj tego :)

user2875404
źródło
1

Jeszcze inne nieco inne rozwiązanie / przypadek.

Używam Xamarin i MvvmCross i próbowałem powiązać UIButton z ViewModel. Miałem UIButton podłączony do gniazdka i TouchUpInside.

Podczas wiązania używam tylko Outletu:

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

Wszystko, co musiałem zrobić, to usunąć połączenie akcji (TouchUpInside) w XCode i to rozwiązało problem.

PS Wydaje mi się, że to w swojej bazie wszystko związane z poprzednimi odpowiedziami, aw szczególności z @Chrisem Kamińskim, ale mam nadzieję, że to komuś pomoże ...

Twoje zdrowie.

YKa
źródło
1

Miałem ten sam problem. Problem polegał na tym, że jeden przycisk miał dwie metody akcji. Stworzyłem pierwszą metodę akcji dla mojego przycisku, a następnie usunąłem go w kontrolerze widoku, ale zapomniałem rozłączyć połączenie w głównej planszy w inspektorze połączeń. Więc kiedy dodałem drugą metodę akcji, były teraz dwie metody akcji dla jednego przycisku, co spowodowało błąd.

Harshil.Chokshi
źródło
1

Dla mnie było to resztkowe połączenie utworzone w programie do tworzenia interfejsów bij ctrl-dragging. Nazwa zerwanego połączenia znajdowała się w dzienniku błędów

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

Miałem akcję połączoną z przyciskiem. Naciśnięcie przycisku spowodowało awarię aplikacji, ponieważ Outlet nie istniał już w moim kodzie. Wyszukiwanie nazwy w dzienniku doprowadziło mnie do tego w storyboardzie. Usunięto go, a awaria zniknęła!

Tom Brinkkemper
źródło
0

Odpowiadam Leonardowi Challisowi, ponieważ brałem również udział w kursie C193P klasy Stanford iOS, podobnie jak użytkownik „oli206”

„Zamykanie aplikacji z powodu nieprzechwyconego wyjątku„ NSInvalidArgumentException ”, przyczyna:„

Problem polegał na tym, że miałem dwukrotnie podłączony przycisk „Enter” na kalkulatorze, a znajomy wskazał, że inspekcja przycisku w Storyboard wykazała, że ​​2 wpisy były w atrybutach „Touch Up Inside”, gdy kliknąłem prawym przyciskiem myszy przycisk „Enter”. Usunięcie jednego z dwóch „Zadań w środku” „Wysłanych wydarzeń” rozwiązało problem.

To pokazało, że problem jest wyzwalany (dla klasy wideo C193P w Przewodniku kalkulatora przy przypisaniu 1) jako 2 wysłane zdarzenia, z których jedno spowodowało wyjątek.

Peter_from_NYC
źródło
Miałem 3 wpisy. :)
1,21 gigawata
0

Może się to zdarzyć, gdy nie przypiszesz ViewController do ViewControllerScene w InterfaceBuilder. Więc ViewController.m nie jest podłączony do żadnej sceny.

Vincent
źródło
0

W tym mój udział. Utknąłem w tym na chwilę, aż zdałem sobie sprawę, że stworzyłem projekt z wyłączonym ARC (Automatic counting reference) . Szybkie ustawienie TAK w tej opcji rozwiązało mój problem.

caiocpricci2
źródło
0

Inną naprawdę głupią przyczyną tego jest posiadanie selektora zdefiniowanego w interfejsie (.h), ale nie w implementacji (.m) (literówka w pe)

jla
źródło
0

Kolejny powód / rozwiązanie do dodania do listy. Ten jest spowodowany przez iOS6.0 (i / lub złe programowanie). W starszych wersjach selektor pasowałby, gdyby typy parametrów były zgodne, ale w iOS 6.0 dostałem awarie we wcześniej działającym kodzie, gdzie nazwa parametru była nieprawidłowa.

Robiłem coś takiego

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

ale w definicji (zarówno .h i .m) miałem

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

To działało dobrze na iOS5, ale nie na 6, nawet ta sama kompilacja wdrożona na różnych urządzeniach.

I tak nie rozumiem, dlaczego kompilator nie mógł mi tego powiedzieć - problem rozwiązany.

Tim T
źródło
0

Może się to również zdarzyć, gdy chcesz ustawić właściwość z kontrolera A na właściwość publiczną w niestandardowej klasie ControllerB, a nie ustawiłeś jeszcze „klasy niestandardowej” w inspektorze tożsamości w scenorysach.

Francisco Gutiérrez
źródło
0

Mój problem i rozwiązanie były inne i pomyślałem, że powinienem zamieścić to tutaj, aby przyszli czytelnicy mogli uratować głowę przed uderzeniem w ścianę.

Przydzielałem różne xib do tego samego UIVIewController i nawet po przeszukaniu wszędzie nie mogłem znaleźć sposobu, aby to poprawić. Następnie sprawdziłem AppDelegate, gdzie initWithNibNamedzwoniłem i widzę, że podczas kopiowania kodu zmieniłem nazwę xib, ale zapomniałem zmienić UIViewControllerklasy. Więc jeśli żadne z rozwiązań nie działa dla Ciebie, sprawdź swoją initWithNibNamemetodę.

Nowicjusz
źródło
0

Przydarzyło mi się to z powodu sprzecznych argumentów ograniczających.

Alex Bedro
źródło