Błąd potwierdzenia w dequeueReusableCellWithIdentifier: forIndexPath:

324

Zrobiłem więc czytnik rss dla mojej szkoły i ukończyłem kod. Uruchomiłem test i dał mi ten błąd. Oto kod, którego dotyczy:

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = 
     [tableView dequeueReusableCellWithIdentifier:CellIdentifier 
                                     forIndexPath:indexPath];
    if (cell == nil) {

        cell = 
         [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle  
                                reuseIdentifier:CellIdentifier];

    }

oto błąd w danych wyjściowych:

2012-10-04 20: 13: 05.356 Czytnik [4390: c07] * Błąd asercji w - [UITableView dequeueReusableCellWithIdentifier: forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:4460 2012-10-04 20: 13: 05.357 Reader [4390: c07] * Zamykanie aplikacji z powodu nieprzechwyconego wyjątku „NSInternalInconsistencyException”, powód: „niezdolność do usunięcia z komórki komórki z identyfikatorem Komórka - musi zarejestrować stalówkę lub klasę dla identyfikatora lub połączyć prototypową komórkę w serii ujęć „ * Pierwsze połączenie rzut stos (0x1c91012 0x10cee7e 0x1c90e78 0xb64f35 0xc7d14 0x39ff 0xd0f4b 0xd101f 0xb980b 0xca19b 0x6692d 0x10e26b0 0x228dfc0 0x228233c 0x228deaf 0x1058cd 0x4e1a6 0x4ccbf 0x4cbd9 0x4be34 0x4bc6e 0x4ca29 0x4f922 0xf9fec 0x46bc4 0x47311 0x2cf3 0x137b7 0x13da7 0x14fab 0x26315 0x2724b 0x18cf8 0x1becdf9 0x1becad0 0x1c06bf5 0x1c06962 0x1c37bb6 0x1c36f44 0x1c36e1b 0x147da 0x1665c 0x2a02 0x2935 ) libc ++ abi.dylib: terminate zwane zgłaszaniem wyjątku

a oto kod wyświetlany na ekranie błędu:

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

proszę pomóż!

Nick Scottman
źródło

Odpowiedzi:

488

Używasz tej dequeueReusableCellWithIdentifier:forIndexPath:metody. Dokumentację dla tej metody mówi w ten sposób:

Ważne: Przed wywołaniem tej metody należy zarejestrować plik klasy lub końcówki za pomocą metody registerNib:forCellReuseIdentifier:lub registerClass:forCellReuseIdentifier:.

Nie zarejestrowałeś stalówki ani klasy dla identyfikatora ponownego wykorzystania "Cell".

Patrząc na twój kod, wydaje się, że spodziewasz się, że metoda dequeue zwróci, niljeśli nie ma komórki, która mogłaby ci dać. Musisz użyć dequeueReusableCellWithIdentifier:do tego zachowania:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

Zauważ, że dequeueReusableCellWithIdentifier:i dequeueReusableCellWithIdentifier:forIndexPath:są to różne metody. Zobacz dokument dla pierwszego i drugiego .

Jeśli chcesz zrozumieć, dlaczego chcesz kiedykolwiek używać dequeueReusableCellWithIdentifier:forIndexPath:, sprawdź poniższe pytania i odpowiedzi .

Rob Mayoff
źródło
166
O MÓJ BOŻE. Dlaczego domyślny szablon Xcode dla UITableViewController automatycznie daje ci dequeueReusableCellWithIdentifier: forIndexPath :? Tak nieprzydatne.
spstanley,
15
( dequeueReusableCellWithIdentifer:forIndexPath:(Wprowadzony w iOS6) to niezłe ulepszenie, ponieważ nie trzeba sprawdzać, czy komórka jest zerowa. (Tak UITableViewControllerdziała podobnie do UICollectionView) Ale tak, denerwujące, że ta zmiana nie jest komentarzem w szablonie i że komunikat potwierdzenia / awarii nie jest bardziej pomocny.
Jason Moore,
2
Przynajmniej można by pomyśleć, że domyślnie byłby to UITableViewCell zamiast implodowania. Baka
BadPirate
13
Ostatni wiersz tej odpowiedzi jest złoty: zostałem ugryziony więcej niż raz, używając, dequeueReusableCellWithIdentifier:forIndexPath:kiedy powinienem był dequeueReusableCellWithIdentifier:.
ele
Ta odpowiedź jest idealna. Mam pytanie: Mam tableViewController jako mój początkowy kontroler widoku. W didSelectRow ... Pcham inny tableViewController na stos nawigacyjny. Dlaczego muszę tylko zarejestrować komórkę dla drugiego tableViewController, a nie początkowego?
ArielSD
137

Myślę, że ten błąd dotyczy rejestracji stalówki lub klasy dla identyfikatora.

Abyś mógł zachować to, co robisz w swojej tableView: funkcja cellForRowAtIndexPath i po prostu dodaj kod poniżej do viewDidLoad:

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];

To zadziałało dla mnie. Mam nadzieję, że to może pomóc.


źródło
3
Jeden mały problem z tym - upewnij się, że identyfikator ponownego użycia pasuje do tego, co skonfigurowałeś w ustawieniach Storyboard dla danej komórki.
James Boutcher
Aby dodać do tego nieco inny przypadek użycia, ponownie wybrałem wiersz w widoku głównym mojego SplitViewController. Ta logika wiersza została ponownie wybrana viewDidLoadi przeniesienie tej logiki do viewDidAppearjej naprawienia.
Craig Conover
Nie można wprowadzić w komórce == zero, więc moja komórka widoku tabeli zawsze jest zerowa.
Solid Soft,
3
swift 3.0: self.tableView.register (UITableViewCell.classForCoder (), forCellReuseIdentifier: "Cell");
norbDEV
68

Chociaż to pytanie jest dość stare, istnieje jeszcze jedna możliwość: jeśli używasz Storyboard, po prostu musisz ustawić CellIdentifier w Storyboard.

Jeśli więc CellIdentifier to „Cell”, po prostu ustaw właściwość „Identifier”: wprowadź opis zdjęcia tutaj

Pamiętaj, aby wyczyścić kompilację po wykonaniu tej czynności. XCode czasami ma pewne problemy z aktualizacjami Storyboard

Sebastian Borggrewe
źródło
3
jesteś niesamowity, sprzątanie robi dużo !! : D
Sandy
2
Uwaga - jeśli używasz identyfikatora innego niż „Komórka”, musisz również zmienić metodę cellForRowAtIndexPath, aby użyć tego identyfikatora w następującym wierszu: statyczny NSString * CellIdentifier = @ „MyCellIdentifier”;
gamozzii
5
Ważny dodatek: widok tabeli musi mieć ustawiony atrybut „Treść” na „Dynamiczne prototypy”, a NIE „Komórki statyczne”
Ted Avery
Ta odpowiedź musi być wyższa. Bardzo pomocny
Sukitha Udugamasooriya,
Czyszczenie kompilacji było niezbędne po aktualizacji Identifiernieruchomości. Dzięki!
Crashalot,
59

miałem ten sam problem z zastąpieniem

static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

   if (cell==nil) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

    }

rozwiązany

iMeMyself
źródło
Dziękuję Ci. To tylko zaoszczędziło mi bólu głowy. =)
Robert,
3
wskazówka: jeśli używasz - (id) dequeueReusableCellWithIdentifier: forIndexPath:, nie musisz sprawdzać, czy komórka jest zerowa. (IOS6>)
Seufagner
właśnie uratował mnie ból głowy. =)
Abo3atef
26

Problem jest najprawdopodobniej, ponieważ konfigurujesz niestandardową UITableViewCellw scenorysie, ale nie używasz scenorysu do tworzenia instancji, UITableViewControllerktóra korzysta z tego UITableViewCell. Na przykład, w MainStoryboard masz UITableViewControllerpodklasę o nazwie MyTableViewControlleri posiada własny dynamikę UITableViewCellnazwie MyTableViewCellz identyfikatorem id „MyCell”.

Jeśli utworzysz niestandardowy w UITableViewControllerten sposób:

 MyTableViewController *myTableViewController = [[MyTableViewController alloc] init];

Nie zarejestruje automatycznie Twojej niestandardowej komórki widoku tabeli. Musisz go ręcznie zarejestrować.

Ale jeśli używasz scenorysu do tworzenia instancji MyTableViewController, w ten sposób:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
MyTableViewController *myTableViewController = [storyboard  instantiateViewControllerWithIdentifier:@"MyTableViewController"];

Miło się dzieje! UITableViewControllerautomatycznie zarejestruje dla Ciebie niestandardową komórkę widoku tabeli, którą zdefiniujesz w serii ujęć.

W metodzie delegowanej „cellForRowAtIndexPath” możesz utworzyć komórkę widoku tabeli w następujący sposób:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

//Configure your cell here ...

return cell;
}

dequeueReusableCellWithIdentifier automatycznie utworzy dla ciebie nową komórkę, jeśli w kolejce recyklingu nie będzie dostępna komórka wielokrotnego użytku.

To koniec!

James Wang
źródło
Wskazówka, że ​​użycie instantiateViewControllerWithIdentifierdo zainicjowania mojego viewController uratowało mi dzień!
Lei Zhang,
uratował mi dzień: prototypowe komórki znajdowały się w sąsiednim VC ze stołem
Anton Tropashko
Jest to uzasadniona przyczyna w moim przypadku.
Nora Alnashwan
19

Dodam tylko, że Xcode 4.5 zawiera nowy dequeueReusableCellWithIdentifier:forIndexPath:
w domyślnym kodzie szablonu - potencjalną gotcha dla programistów oczekujących starszej dequeueReusableCellWithIdentifier:metody.

Brian Shriver
źródło
Ukłuł mnie! Teraz będę wiedział lepiej. ;)
spstanley
18

W swojej serii ujęć powinieneś ustawić „Identyfikator” swojej prototypowej komórki, aby był taki sam jak Twój „Cell” CellReuseIdentifier. Wtedy nie dostaniesz tej wiadomości ani nie będziesz musiał wywoływać funkcji registerClass:.

Steven
źródło
2
Gotcha! Gdzie jest przycisk „100 upvotes”. To jest prawdziwe rozwiązanie.
Jojo.Lechelt,
Można by pomyśleć, że dodanie nowego widoku tabeli do scenorysu zapewni domyślny identyfikator - „Komórka”. Jest to bardzo łatwe do przeoczenia, zwłaszcza jeśli używasz tak zwanego „wolnego kodu” w tableView: cellForRowAtIndexPath!
ushika
18

Rozwiązanie Swift 2.0:

Musisz przejść do Inspektora atrybutów i dodać nazwę swojej komórki Identyfikator:

wprowadź opis zdjęcia tutaj

Następnie musisz dopasować swój identyfikator do dequeue w następujący sposób:

let cell2 = tableView.dequeueReusableCellWithIdentifier("ButtonCell", forIndexPath: indexPath) as! ButtonCell

Alternatywnie

Jeśli pracujesz ze stalówką, może być konieczne zarejestrowanie swojej klasy w cellForRowAtIndexPath:

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

    tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SwitchCell")

    // included for context            
    let cell = tableView.dequeueReusableCellWithIdentifier("SwitchCell", forIndexPath:indexPath) as! SwitchCell

    //... continue    
}

Odwołanie do klasy UITableView firmy Apple mówi:

Przed usunięciem kolejki z dowolnych komórek należy wywołać tę metodę lub metodę registerNib: forCellReuseIdentifier:, aby powiedzieć widokowi tabeli, jak tworzyć nowe komórki. Jeśli komórka określonego typu nie znajduje się obecnie w kolejce do ponownego użycia, widok tabeli wykorzystuje dostarczone informacje do automatycznego utworzenia nowego obiektu komórki.

Jeśli wcześniej zarejestrowałeś plik klasy lub stalówki z tym samym identyfikatorem ponownego wykorzystania, klasa określona w parametrze cellClass zastępuje stary wpis. Możesz podać zero dla cellClass, jeśli chcesz wyrejestrować klasę z określonego identyfikatora ponownego użycia.

Oto kod z frameworka Apples Swift 2.0:

// Beginning in iOS 6, clients can register a nib or class for each cell.
// If all reuse identifiers are registered, use the newer -dequeueReusableCellWithIdentifier:forIndexPath: to guarantee that a cell instance is returned.
// Instances returned from the new dequeue method will also be properly sized when they are returned.

@available(iOS 5.0, *)
func registerNib(nib: UINib?, forCellReuseIdentifier identifier: String)

@available(iOS 6.0, *)
func registerClass(cellClass: AnyClass?, forCellReuseIdentifier identifier: String)
Dan Beaulieu
źródło
Nie rozumiem, skąd SwitchCell.selfpochodzi?
Gert Cuykens,
@GertCuykens SwitchCell jest moim niestandardowym UITableViewCell
Dan Beaulieu
1
W tej chwili jestem z dala od komputera Mac, ale zdecydowanie mogę go zaktualizować, gdy wrócę do domu.
Dan Beaulieu
1
Zastąpienie go UITableViewCell.selfwydaje się działać dla mnie. Może dodaj notatkę w odpowiedzi
Gert Cuykens
@GertCuykens dzięki za zwrócenie na to uwagi, zmieniłem SwitchCell.self na UITableViewCell.self
Dan Beaulieu
3

Jeśli korzystasz z niestandardowych komórek statycznych, po prostu skomentuj tę metodę:

//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//    static NSString *CellIdentifier = @"notificationCell";
//    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//    return cell;
//}

i nadaj komórkom identyfikator w „Inspektorze atrybutów” w serii ujęć.

Francisco Gutiérrez
źródło
3

Daję ci odpowiedź zarówno w Celu C, jak i Swifcie, zanim to powiem

Jeśli korzystamy z dequeueReusableCellWithIdentifier:forIndexPath:, musimy zarejestrować plik klasy lub stalówki za pomocą metody registerNib: forCellReuseIdentifier: lub registerClass: forCellReuseIdentifier: przed wywołaniem tej metody jako Apple Documnetation:

Więc dodajemy registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier:

Po zarejestrowaniu klasy dla określonego identyfikatora i konieczności utworzenia nowej komórki, ta metoda inicjuje komórkę, wywołując jej metodę initWithStyle: reuseIdentifier:. W przypadku komórek opartych na stalówce metoda ta ładuje obiekt komórki z dostarczonego pliku stalówki. Jeśli istniejąca komórka była dostępna do ponownego użycia, metoda ta wywołuje metodę preparForReuse komórki.

w metodzie viewDidLoad powinniśmy zarejestrować komórkę

Cel C

OPCJA 1:

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];

OPCJA 2:

[self.tableView registerNib:[UINib nibWithNibName:@"CustomCell" bundle:nil] forCellReuseIdentifier:@"cell"];

w powyższym kodzie nibWithNibName:@"CustomCell"podaj nazwę stalówki zamiast mojej nazwy stalówki CustomCell

SZYBKI

OPCJA 1:

tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")

OPCJA 2:

tableView.registerNib(UINib(nibName: "NameInput", bundle: nil), forCellReuseIdentifier: "Cell") 

w powyższym kodzie nibName:"NameInput"podaj nazwę swojej stalówki

użytkownik3182143
źródło
3

Praca z Swift 3.0:

override func viewDidLoad() {
super.viewDidLoad()

self.myList.register(UINib(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
}



public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myList.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! MyTableViewCell

return cell
}
norbDEV
źródło
2

Wczoraj spędziłem godziny, zastanawiając się, dlaczego moja programowo wygenerowana tabela uległa awarii na [myTable setDataSource: self]; Komentowanie i wyskakiwanie pustej tabeli było w porządku, ale zawieszało się za każdym razem, gdy próbowałem dotrzeć do źródła danych;

Delegację skonfigurowałem w pliku h: @interface myViewController: UIViewController

Miałem kod źródłowy danych w mojej implementacji i nadal BOOM !, awaria za każdym razem! DZIĘKUJEMY za „xxd” (nr 9): dodanie tej linii kodu rozwiązało to dla mnie! W rzeczywistości uruchamiam tabelę za pomocą przycisku IBAction, więc oto mój pełny kod:

    - (IBAction)tapButton:(id)sender {

    UIViewController* popoverContent = [[UIViewController alloc]init];

    UIView* popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)];
    popoverView.backgroundColor = [UIColor greenColor];
    popoverContent.view = popoverView;

    //Add the table
    UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)         style:UITableViewStylePlain];

   // NEXT THE LINE THAT SAVED MY SANITY Without it the program built OK, but crashed when      tapping the button!

    [table registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
    table.delegate=self;
    [table setDataSource:self];
    [popoverView addSubview:table];
    popoverContent.contentSizeForViewInPopover =
    CGSizeMake(200, 300);

    //create a popover controller
    popoverController3 = [[UIPopoverController alloc]
                          initWithContentViewController:popoverContent];
    CGRect popRect = CGRectMake(self.tapButton.frame.origin.x,
                                self.tapButton.frame.origin.y,
                                self.tapButton.frame.size.width,
                                self.tapButton.frame.size.height);


    [popoverController3 presentPopoverFromRect:popRect inView:self.view   permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];



   }


   #Table view data source in same m file

   - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
   {
    NSLog(@"Sections in table");
    // Return the number of sections.
    return 1;
   }

   - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
  {
    NSLog(@"Rows in table");

    // Return the number of rows in the section.
    return myArray.count;
   }

   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath    *)indexPath
    {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    NSString *myValue;

    //This is just some test array I created:
    myValue=[myArray objectAtIndex:indexPath.row];

    cell.textLabel.text=myValue;
    UIFont *myFont = [ UIFont fontWithName: @"Arial" size: 12.0 ];
    cell.textLabel.font  = myFont;

    return cell;
   }

Nawiasem mówiąc: przycisk musi być połączony z jako IBAction i jako IBOutlet, jeśli chcesz zakotwiczyć do niego popover.

UIPopoverController * popoverController3 jest zadeklarowany w pliku H bezpośrednio po @interface między {}

Simone
źródło
2

FWIW, dostałem ten sam błąd, gdy zapomniałem ustawić identyfikator komórki w serii ujęć. Jeśli to jest twój problem, w serii ujęć kliknij komórkę widoku tabeli i ustaw identyfikator komórki w edytorze atrybutów. Upewnij się, że ustawiony tutaj identyfikator komórki jest taki sam jak

static NSString *CellIdentifier = @"YourCellIdenifier";
honkskillet
źródło
2

Miałem ten sam problem, miałem ten sam błąd i dla mnie działało to tak:

[self.tableView registerNib:[UINib nibWithNibName:CELL_NIB_HERE bundle: nil] forCellReuseIdentifier:CELL_IDENTIFIER_HERE];

Może przyda się komuś innemu.

CarmenA
źródło
2

Ustawiłem wszystko poprawnie w serii ujęć i wykonałem czystą kompilację, ale wciąż pojawiał się błąd „ muszę zarejestrować stalówkę lub klasę dla identyfikatora lub podłączyć prototypową komórkę w serii ujęć

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];

Poprawiono błąd, ale wciąż mam stratę. Nie używam „niestandardowej komórki”, tylko widok z osadzonym widokiem tabeli. Zadeklarowałem kontroler widoku jako delegat i źródło danych i upewniłem się, że identyfikator komórki pasuje do pliku. co tu się dzieje?

FrostyL
źródło
1

To może wydawać się głupie dla niektórych osób, ale mnie zrozumiało. Otrzymywałem ten błąd i problem polegał na tym, że próbowałem użyć komórek statycznych, ale dynamicznie dodawałem więcej rzeczy. Jeśli wywołujesz tę metodę, twoje komórki muszą być dynamicznymi prototypami. Wybierz komórkę w serii ujęć i pod Inspektorem atrybutów, pierwsza rzecz mówi „Treść” i powinieneś wybrać dynamiczne prototypy, które nie są statyczne.

Chase Roberts
źródło
DZIĘKUJĘ CI! To był dokładnie mój problem.
Isaiah Turner
1

Tylko uzupełnienie odpowiedzi: może być czas, aby wszystko dobrze ustawić, ale możesz przypadkowo dodać do ciebie kilka innych interfejsów użytkownika .xib, takich jak UIButton: wprowadź opis zdjęcia tutaj Wystarczy usunąć dodatkowy interfejs, to działa.

DrustZ
źródło
1

Upewnij się, że CellIdentifier == identyfikator komórki w serii ujęć, obie nazwy są takie same. Mam nadzieję, że to zadziała u ciebie

Anargit garg
źródło
0

W moim przypadku do awarii doszło, kiedy zadzwoniłemdeselectRowAtIndexPath:

Linia była [tableView deselectRowAtIndexPath:indexPath animated:YES];

Zmieniając go na [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; FIXED MY PROBLEM!

Mam nadzieję, że to pomoże każdemu

Offek
źródło
0

W Swift ten problem można rozwiązać, dodając następujący kod do swojego

viewDidLoad

metoda.

tableView.registerClass(UITableViewCell.classForKeyedArchiver(), forCellReuseIdentifier: "your_reuse_identifier")
arango_86
źródło
-1

Wystąpił ten błąd Identyfikator ponownego użycia komórki bc był niepoprawny - błąd nowicjusza, ale zdarza się: 1. Sprawia, że ​​identyfikator ponownego użycia komórki SURE nie ma błędów ortograficznych ani brakujących liter. 2. W tym samym wierszu nie zapomnij o liczeniu wielkich liter. 3. Zera nie są „O” (Ohs)

John Pitts
źródło