Jak mogę debugować błąd „nierozpoznany selektor wysłany do instancji”

101

Tworzę niestandardowy widok komórki tabeli dla mojego widoku tabeli. Po szybkim połączeniu widoku obrazu niestandardowej komórki (w scenorysie) z moim kodem, pojawia się następujący błąd.

[UITableViewCellContentView image]: unrecognized selector sent to instance 0x7fb4fad7fd20'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010ccbb3f5 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010e7e9bb7 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010ccc250d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x000000010cc1a7fc ___forwarding___ + 988
    4   CoreFoundation                      0x000000010cc1a398 _CF_forwarding_prep_0 + 120
    5   UIKit                               0x000000010d7d8881 -[UITableViewCell _marginWidth] + 151
    6   UIKit                               0x000000010d7ca23d -[UITableViewCell _separatorFrame] + 70
    7   UIKit                               0x000000010d7ca6fa -[UITableViewCell _updateSeparatorContent] + 360
    8   UIKit                               0x000000010d7d4e85 -[UITableViewCell _setSectionLocation:animated:forceBackgroundSetup:] + 1174
    9   UIKit                               0x000000010d634ea8 __53-[UITableView _configureCellForDisplay:forIndexPath:]_block_invoke + 1822
    10  UIKit                               0x000000010d5b5eae +[UIView(Animation) performWithoutAnimation:] + 65
    11  UIKit                               0x000000010d63477b -[UITableView _configureCellForDisplay:forIndexPath:] + 312
    12  UIKit                               0x000000010d63bcec -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 533
    13  UIKit                               0x000000010d61b7f1 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2846
    14  UIKit                               0x000000010d63165c -[UITableView layoutSubviews] + 213
    15  UIKit                               0x000000010d5be199 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 521
    16  QuartzCore                          0x00000001114b6f98 -[CALayer layoutSublayers] + 150
    17  QuartzCore                          0x00000001114abbbe _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
    18  QuartzCore                          0x00000001114aba2e _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
    19  QuartzCore                          0x0000000111419ade _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 242
    20  QuartzCore                          0x000000011141abea _ZN2CA11Transaction6commitEv + 390
    21  QuartzCore                          0x000000011141b255 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 89
    22  CoreFoundation                      0x000000010cbf0347 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    23  CoreFoundation                      0x000000010cbf02a0 __CFRunLoopDoObservers + 368
    24  CoreFoundation                      0x000000010cbe60d3 __CFRunLoopRun + 1123
    25  CoreFoundation                      0x000000010cbe5a06 CFRunLoopRunSpecific + 470
    26  GraphicsServices                    0x0000000110daa9f0 GSEventRunModal + 161
    27  UIKit                               0x000000010d545550 UIApplicationMain + 1282
    28  TestWork                          0x000000010caa432e top_level_code + 78
    29  TestWork                          0x000000010caa436a main + 42
    30  libdyld.dylib                       0x000000010efc3145 start + 1
    31  ???                                 0x0000000000000001 0x0 + 1
)

Czy możesz mi powiedzieć, jak rozwiązać ten błąd?

Dziękuję Ci.

Dodaję punkt przerwania wyjątku w moim projekcie.

To jest linia, w której się łamie.

  override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = self.tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as ItemTableViewCell  <---------------

Ale nie używam słowa „obraz” w moim kodzie.

n179911
źródło
2
dzwonisz image]gdzieś .. ale na niewłaściwym obiekcie. pierwsza linia błędu mówi o tym dużo
ccwasden
1
Przestań wywoływać [image] na UITableViewCellContentView - to by to naprawić. Pokaż nam kod, który powoduje tę awarię.
Grzegorz Krukowski
1
Myślę, że użyłeś jakiegoś obrazu w tableViewCell, ale ten obraz może nie znajdować się w Twoim pakiecie.
Nand Parikh

Odpowiedzi:

102

Spróbuj ustawić symboliczny punkt przerwania -[NSObject(NSObject) doesNotRecognizeSelector:]. Wystarczy kliknąć [+]w lewym dolnym rogu Nawigatora punktów przerwania, aby dodać punkt przerwania. Następnie kliknij „Dodaj symboliczny punkt przerwania”. Ponowne odtworzenie awarii powinno dać lepsze wyobrażenie o tym, gdzie w kodzie występuje problem.

wprowadź opis obrazu tutaj

dbart
źródło
17
Można też po prostu dodać wyjątkowy punkt przerwania .
rebello95
1
Uratowałem mój dzień, brachu.
AntiMoron
1
Dziękuję, że jest tak pożytecznie
Mohd Sadham
35

Możesz łatwo śledzić takie awarie za pomocą Exception Breakpoints.

Otwórz Breakpoint Navigatori dodaj plik

wprowadź opis obrazu tutaj

Po dodaniu punktu przerwania wyjątku opcja zostanie otwarta, aby wybrać plik Exception.

wprowadź opis obrazu tutaj

Wybierz Objective-C.

Uruchom kod i zawieszaj aplikację, punkt przerwania zatrzyma Cię do punktu, w którym kod ulega awarii.

Vatsal K.
źródło
Dzieje się to w linii 1. AppDelegate. I co teraz? :(
Daniel Springer
Czy możesz pokazać część swojego kodu napisanego w AppDelegate? Gdzie wstrzymuje punkt przerwania. A także dzienniki.
Vatsal K
zatrzymuje się w linii 1, gdzie deklarowany jest delegat aplikacji
Daniel Springer
Istnieją przypadki, w których zatrzymuje się z powodu niektórych frameworków, ale nie martw się, że może być konieczne naciśnięcie przycisku Kontynuuj 3-4 razy, aby uruchomić aplikację.
Vatsal K
To nie jest błąd w takim przypadku, niektóre stare frameworki powodują tego rodzaju problem. Spróbuj zaktualizować stare frameworki do nowych / zaktualizowanych. To powinno rozwiązać problem.
Vatsal K
30

Krytycznym pierwszym krokiem jest przeanalizowanie komunikatu o błędzie:

[UITableViewCellContentView image]: unrecognized selector sent to instance

Oznacza to, że „wiadomość” imagezostała „wysłana” do obiektu klasy UITableViewCellContentView. (Innymi słowy, podjęto próbę wywołania metody imagena obiekcie klasy UITableViewCellContentView.)

Pierwszą rzeczą, o którą należy zapytać, jest „Czy to w ogóle ma sens?” Możliwe, że nazwana klasa ma Imagemetodę, ale nie imagemetodę, dlatego w wywołaniu użyto złej nazwy metody. Lub może być tak, że nazwana metoda to someMethod:someParm:, ale klasa implementuje someMethod:someParm:anotherParm:, co oznacza, że ​​parametr został pominięty w wywołaniu.

Jednak najczęściej nazwana klasa nie ma żadnej metody, nawet niejasno przypominającej nazwaną metodę, co oznacza, że ​​w jakiś sposób w nieudanym wywołaniu użyto wskaźnika do niewłaściwego obiektu.

Na przykład można zrobić:

NSArray* myArray = [myDictionary objectForKey:@"values"];
NSString* myString = [myArray objectAtIndex:5];

I uzyskaj błąd w następujący sposób:

[__NSDictionaryI objectAtIndex:] unrecognized selector sent to instance

ponieważ obiekt pobrany z myDictionarybył w rzeczywistości NSDictionary, a nie NSArray, którego oczekiwano.

Niestety, najbardziej zagmatwane jest to, że tego rodzaju błąd pojawia się głęboko w kodzie systemowym interfejsu użytkownika, a nie we własnym kodzie. Może się to zdarzyć, gdy w jakiś sposób przekazałeś niewłaściwy obiekt do interfejsu systemu lub być może skonfigurowałeś niewłaściwą klasę w Interface Builder lub gdziekolwiek.

Hot Licks
źródło
6

Innym możliwym powodem jest to, że oryginalny obiekt został zniszczony, a następnie przydzielono inny obiekt pod ten sam adres pamięci. Następnie kod wysyła wiadomość, myśląc, że nadal ma wskaźnik do starego obiektu, a Objective-C zgłasza wyjątek, ponieważ nowy obiekt nie rozumie tej wiadomości.

Aby zdiagnozować ten problem, uruchom Profiler z wykrywaniem „Zombie”.

Bryan
źródło
2

Swift 5.0

Możesz użyć introspekcji, aby dowiedzieć się, czy obiekt odpowiada na określony selektor, czy nie.

let canWork = yourObject.respondsToSelector(Selector("image"))   // true

Tylko jeśli to prawda, że ​​kod będzie działał ... w przeciwnym razie na pewno ulegnie awarii

Saranjith
źródło
1

W tych scenariuszach uważam, że pomocne jest przyjrzenie się dwóm rzeczom

  1. Stos wywołań
  2. Zmienne lokalne (i ich typy) w każdej ramce stosu

Kiedy mam ten błąd, zwykle dzieje się tak, ponieważ wysłałem wiadomość do wystąpienia typu A, kiedy spodziewałem się typu B.

W tym konkretnym scenariuszu możesz nie spełniać wymagania klasy nadrzędnej (biorąc pod uwagę, że Twoje wystąpienie ItemTableViewCell najprawdopodobniej dziedziczy).

Czy możesz pokazać nam kod swojej klasy ItemTableViewCell?

ABC
źródło
1

Aby zadeklarować zmienną, możesz użyć następującego kodu:

let noteListTableViewCellobject = "NoteListTableViewCell";` `// Note listTablecell create custom cell`

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {

    var cell:NoteListTableViewCell? = tableView.dequeueReusableCellWithIdentifier(noteListTableViewCellobject) as? NoteListTableViewCell

    if (cell == nil) {
        let nib:Array = NSBundle.mainBundle().loadNibNamed("NoteListTableViewCell", owner: self, options: nil)
        cell = nib[0] as? NoteListTableViewCell
    }
}
Półka Yogesh
źródło
0

Miałem ten sam problem i to działało dla mnie:

Zastąp isEqual w swoim SKScene:

- (BOOL)isEqual:(id)other {

    if (![other isMemberOfClass:[SKScene class]]) {
        return false;
    }
    return [super isEqual:other];
}
Razvan
źródło
0

Musisz przejść, indexPathaby zadeklarować obiekt komórki tableview.

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)

    return cell
}
Rohit Parsana
źródło