Невдача твердження в dequeueReusableCellWithIdentifier: forIndexPath:


324

Тому я робив читацьку програму для своєї школи і закінчував код. Я запустив тест, і це дало мені таку помилку. Ось код, на який він посилається:

- (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];

    }

ось помилка у виході:

2012-10-04 20: 13: 05.356 Читач [4390: c07] * Невдача твердження в - [UITableView dequeueReusableCellWithIdentifier: forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:4460 2012-10-04 20: 13: 05.357 Читач [4390: c07] * Закінчення програми через невиконаний виняток "NSInternalInconsistencyException", причина: "не вдається видалити клітинку з ідентифікатором Cell" - потрібно зареєструвати нитку або клас для ідентифікатора або підключити прототип комірки в дошці розкадрування ' * Перший стек кинути виклик: (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: припиняє називати кидання винятком

і ось код, який він відображається на екрані помилок:

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

будь ласка, допоможіть!


Відповіді:


488

Ви використовуєте dequeueReusableCellWithIdentifier:forIndexPath:метод. Документація для цього методу говорить , що це:

Важливо: перед тим, як викликати цей метод, ви повинні зареєструвати файл класу чи nib за допомогою методу registerNib:forCellReuseIdentifier:або registerClass:forCellReuseIdentifier:.

Ви не зареєстрували ниб або клас для ідентифікатора повторного використання "Cell".

Дивлячись на ваш код, ви, здається, очікуєте, що метод dequeue повернеться, nilякщо в ньому немає комірки, яка б вам надіслала. Вам потрібно використовувати dequeueReusableCellWithIdentifier:для такої поведінки:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

Зауважте, що це dequeueReusableCellWithIdentifier:і dequeueReusableCellWithIdentifier:forIndexPath:різні методи. Див. Doc для першого та останнього .

Якщо ви хочете зрозуміти, чому ви хочете коли-небудь використовувати dequeueReusableCellWithIdentifier:forIndexPath:, перегляньте це питання .


166
О БОЖЕ МІЙ. Чому шаблон за замовчуванням Xcode для UITableViewController автоматично дає вам dequeueReusableCellWithIdentifier: forIndexPath :? Так непомітно.
spstanley

15
dequeueReusableCellWithIdentifer:forIndexPath:(Введено в iOS6) є поліпшення добре, так як вам не потрібно , щоб перевірити , якщо осередок дорівнює нулю. (Так UITableViewControllerпрацює аналогічно UICollectionView) Але так, прикро, що ця зміна не коментується в шаблоні і що повідомлення про твердження / збій не є більш корисним.
Джейсон Мур

2
Принаймні, ви можете подумати, що це буде за замовчуванням UITableViewCell замість імплодування. Бака.
BadPirate

13
Останній рядок цієї відповіді - золотий: мене не раз кусали, dequeueReusableCellWithIdentifier:forIndexPath:коли я мав використовувати dequeueReusableCellWithIdentifier:.
еле

Ця відповідь ідеальна. У мене виникає питання: у мене є початковий контролер перегляду tableViewController. На didSelectRow ... Я натискаю інший tableViewController на навігаційний стек. Чому я маю лише зареєструвати комірку для другої tableViewController, а не початкової?
ArielSD

137

Я думаю, що ця помилка пов'язана з реєстрацією вашого nib або class для ідентифікатора.

Щоб ви могли зберегти те, що ви робите, у своїй функції tableView: cellForRowAtIndexPath та просто додайте код нижче у свій viewDidLoad:

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

Це працює для мене. Сподіваюся, це може допомогти.


3
Один невеликий готч із цим - переконайтесь, що ідентифікатор повторного використання відповідає тому, що ви встановили у своїх настройках дошки розкадрування для відповідної комірки.
Джеймс Батчер

Для того, щоб додати це до дещо іншого випадку використання, я перебирав рядок у головному перегляді мого SplitViewController. Ця логіка viewDidLoadперебирання рядків була в і рухає цю логіку для viewDidAppearїї виправлення.
Крейг Коновер

Він не міг увійти в клітинку == нуль, тому моя клітинка tableview завжди дорівнює нулю.
Твердий м'який

3
swift 3.0: self.tableView.register (UITableViewCell.classForCoder (), forCellReuseIdentifier: "Cell");
norbDEV

68

Хоча це запитання досить старе, є й інша можливість: Якщо ви використовуєте дошки розкадрувань, вам просто потрібно встановити CellIdentifier на аркуші розкадри.

Отже, якщо ваш CellIdentifier є "Cell", просто встановіть властивість "Identifier": введіть тут опис зображення

Обов’язково очистіть свою конструкцію після цього. XCode іноді має деякі проблеми з оновленнями Storyboard


3
Ви дивовижні, прибирання робить багато !! : D
Сенді

2
Примітка - якщо ви використовуєте ідентифікатор, відмінний від "Cell", вам також знадобиться змінити метод CellForRowAtIndexPath, щоб використовувати цей ідентифікатор у наступному рядку: статичний NSString * CellIdentifier = @ "MyCellIdentifier";
gamozzii

5
Одне важливе доповнення до цього: Перегляд таблиці повинен мати свій атрибут "Вміст", встановлений на "Динамічні прототипи", а не на "Статичні клітини"
Тед Евері

Цю відповідь потрібно досягти вище. Дуже корисно
Sukitha Udugamasooriya

Очищення складання було важливим після оновлення Identifierвластивості. Дякую!
Crashalot

59

У мене була та сама проблема із заміною

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

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

    }

вирішено


Дякую. Це просто врятувало мені головний біль. =)
Роберт

3
порада: якщо ви використовуєте - (id) dequeueReusableCellWithIdentifier: forIndexPath:, не потрібно перевіряти, чи клітинка є нульовою. (
IOS6

просто врятував мені головний біль. =)
Abo3atef

26

Проблема є, швидше за все, тим, що ви налаштовуєте користувальницьку UITableViewCellв раскадровці, але ви не використовуєте розкадровку для інстанції вашої, UITableViewControllerяка використовує це UITableViewCell. Наприклад, в MainStoryboard у вас є UITableViewControllerпідклас, який називається, MyTableViewControllerі призначений для користувача динамічний UITableViewCellвиклик MyTableViewCellз ідентифікатором ідентифікатора "MyCell".

Якщо ви створили такий звичай UITableViewController:

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

Він не автоматично зареєструє вашу власну таблицю viewviewcell. Ви повинні його вручну зареєструвати.

Але якщо ви використовуєте раскадровку для інстанції MyTableViewController, виконайте такі дії:

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

Приємна річ буває! UITableViewControllerавтоматично зареєструє вашу власну осередку перегляду таблиць, яку ви визначите у дошці розкадрувань.

У вашому методі делегування "cellForRowAtIndexPath" ви можете створити вам клітинку подання таблиці таким чином:

- (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 автоматично створить нову клітинку для вас, якщо в черзі на переробку немає наявної комірки для багаторазового використання.

Тоді ви готові!


Порада, що за допомогою instantiateViewControllerWithIdentifierinit my viewController врятувала мені день!
Лей Чжан

врятував мій день: осередки-прототипи були в сусідньому ВК із таблицею
Антон Тропашко

Це розумна причина в моєму випадку.
Нора Алнашван

19

Я просто додам, що Xcode 4.5 включає новий dequeueReusableCellWithIdentifier:forIndexPath:
у свій шаблон шаблону за замовчуванням - потенційний прихильник для розробників, які очікують на старіший dequeueReusableCellWithIdentifier:метод.


Укусив мене! Тепер я краще буду знати. ;)
спстанлей

18

У вашій розгорнутій дошці ви повинні встановити "Ідентифікатор" комірки прототипу таким самим, як ваш CellReuseIdentifier "Cell". Тоді ви не отримаєте це повідомлення або потрібно зателефонувати в функцію registerClass:.


2
Отримав! Де знаходиться кнопка "100 оновлень". Це справжнє рішення.
Jojo.Lechelt

Ви можете подумати, що додавання нової tableView в дошку розкадрування забезпечить ідентифікатор за замовчуванням - "Cell". Це так легко не помітити, особливо якщо ви використовуєте так званий "безкоштовний код" у tableView: cellForRowAtIndexPath!
ushika

18

Рішення Swift 2.0:

Вам потрібно зайти до свого інспектора атрибутів і додати ім’я для вашого ідентифікатора клітин:

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

Тоді вам потрібно зробити так, щоб ваш ідентифікатор збігався з вашим декею таким чином:

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

Як варіант

Якщо ви працюєте з нібом, можливо, вам доведеться зареєструвати свій клас у вашій стільниковіForForWowAtIndexPath:

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    
}

У довідці про клас UITableView від Apple відзначається:

Перш ніж вилучити будь-які комірки, зателефонуйте цьому методу або registerNib: forCellReuseIdentifier: метод, щоб повідомити подання таблиці, як створити нові комірки. Якщо комірка вказаного типу наразі не стоїть у черзі повторного використання, подання таблиці використовує надану інформацію для автоматичного створення нового об'єкта комірки.

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

Ось код із рамки 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)

Я не розумію, звідки SwitchCell.selfберуться?
Герт Куйкенс

@GertCuykens SwitchCell - мій користувальницький UITableViewCell
Дан Болье

1
Я зараз далеко від свого Mac, але я точно можу оновити його, коли повернусь додому.
Dan Beaulieu

1
Заміни його на, UITableViewCell.selfздається, працюють для мене. Можливо, додайте примітку у відповідь
Герт Куйкенс

Дякую @GertCuykens за те, що вказав, що я змінив SwitchCell.self на UITableViewCell.self
Dan Beaulieu

3

Якщо ви збираєтеся зі спеціальними статичними клітинками, просто прокоментуйте цей метод:

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

і дайте клітинкам ідентифікатор у "Інспекторі атрибутів" у розгортці.


3

Я даю вам відповідь і в цілі C, і в Swift. Перед цим я хочу сказати

Якщо ми використовуємо dequeueReusableCellWithIdentifier:forIndexPath:, ми повинні зареєструвати файл класу або nib за допомогою registerNib: forCellReuseIdentifier: або registerClass: forCellReuseIdentifier: перед тим, як викликати цей метод як Apple Documnetation Says

Тож додамо registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier:

Після того, як ми зареєстрували клас для вказаного ідентифікатора, і повинна бути створена нова комірка, цей метод ініціалізує клітинку, викликаючи її метод initWithStyle: reuseIdentifier:. Для осередків на основі nib цей метод завантажує об'єкт комірки з наданого файлу nib. Якщо наявна комірка була доступна для повторного використання, цей метод викликає замість цього метод pripravForReuse комірки.

у методі viewDidLoad ми повинні зареєструвати комірку

Мета C

ВАРІАНТ 1:

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

ВАРІАНТ 2:

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

у наведеному вище коді nibWithNibName:@"CustomCell"вкажіть своє ім'я ніб замість мого прізвища CustomCell

SWIFT

ВАРІАНТ 1:

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

ВАРІАНТ 2:

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

у наведеному вище коді nibName:"NameInput"вкажіть назву вашої ручки


3

Робота зі 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
}

2

Я провів години минулої ночі, працюючи над тим, чому моя програмно створена таблиця вийшла з ладу [myTable setDataSource: self]; Було гаразд, коментуючи та вискакуючи порожній стіл, але зазнав аварії кожного разу, коли я намагався дістатись до джерела даних;

У мене була створена делегація у h-файлі: @interface myViewController: UIViewController

Я мав вихідний код даних у моїй реалізації та все ще БУМ !, щоразу виходить з ладу! ДЯКУЙТЕ "xxd" (nr 9): додавання цього рядка коду вирішило це для мене! Насправді я запускаю таблицю з кнопки IBAction, тому ось мій повний код:

    - (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;
   }

До речі: кнопка повинна бути пов'язана як з IBAction, так і як з IBOutlet, якщо ви хочете прив’язати до неї попу.

UIPopoverController * popoverController3 оголошується у файлі H безпосередньо після @interface між {}


2

FWIW, я отримав цю саму помилку, коли забув встановити ідентифікатор комірок у розкадровці. Якщо це ваша проблема, тоді на панелі розкадрування натисніть на комірку перегляду таблиці та встановіть ідентифікатор комірки в редакторі атрибутів. Переконайтесь, що ідентифікатор комірок, який ви встановили тут, такий же, як

static NSString *CellIdentifier = @"YourCellIdenifier";

2

У мене була та сама проблема, була однакова помилка, і для мене вона працювала так:

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

Можливо, це буде корисним для когось іншого.


2

Я все правильно встановив на Дошці розкадрувань і зробив чисту збірку, але продовжував отримувати помилку: " повинен зареєструвати нитку або клас для ідентифікатора або з'єднати комірку прототипу в табло "

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

Виправлено помилку, але я все ще втрачаю. Я не використовую "власну клітинку", а лише перегляд із вбудованим переглядом таблиці. Я оголосив viewcontroller як делегат і джерело даних і переконався, що ідентифікатор комірок відповідає файлу. що тут відбувається?


1

Деяким людям це може здатися дурним, але це мене зрозуміло. Я отримував цю помилку, і проблема для мене полягала в тому, що я намагався використовувати статичні комірки, але потім динамічно додав більше речей. Якщо ви називаєте цей метод, ваші клітини повинні бути динамічними прототипами. Виберіть комірку в аркуші розкадрування та в інспекторі атрибутів, перше, що написано "Вміст", і вам слід вибрати динамічні прототипи, не статичні.


ДЯКУЮ ТОБІ! Це була саме моя проблема.
Ісая Тернер

1

Просто доповнення відповідей: Може бути час, коли ви все налаштуєте правильно, але ви можете випадково додати в себе ще якісь інтерфейси .xib, наприклад UIButton: введіть тут опис зображення Просто видаліть додатковий інтерфейс, він працює.


1

Переконайтесь, що ідентифікатор CellIdentifier == комірки в таблиці розмов, обидва імена однакові. Сподіваюся, це працює для u


0

У моєму випадку аварія сталася, коли я зателефонувавdeselectRowAtIndexPath:

Лінія була [tableView deselectRowAtIndexPath:indexPath animated:YES];

Змінивши його на [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; ФІКСОВАНУ МОЮ ПРОБЛЕМУ!

Сподіваюсь, це допомагає комусь


0

У Swift цю проблему можна вирішити, додавши у свій код наступний код

viewDidLoad

метод.

tableView.registerClass(UITableViewCell.classForKeyedArchiver(), forCellReuseIdentifier: "your_reuse_identifier")

-1

Натрапив на цей ідентифікатор повторного використання клітинки Bc був помилковим - помилка новичка, але трапляється: 1. Здійснює ідентифікатор повторного використання комірки SURE без помилок написання або відсутніх літер. 2. У цьому ж рядку не забудьте підрахунок капіталізації. 3. Нулі не є "O" s (О)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.