8

I have a custom UITableViewCell subclass and I'm trying to add a pinch gesture recognizer using Interface Builder to one of the views. My app crashes with:

2016-09-11 17:37:22.425 MYAPPNAME[4619:1284144] *** Assertion failure in -[ULFeedView _dequeueReusableViewOfType:withIdentifier:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.12/UITableView.m:6539

I've tried different gesture recognizers (e.g. tap recognizers) and different subviews, but they all crash my app.

An interesting observation: It doesn't crash if I add the recognizer to a view programmatically at awakeFromNib.

Here is some methods that might be relevant:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    if(indexPath.section != SECTION_CONTENT){
        return; //index path section is NOT equal to SECTION CONTENT for the cell in question, so it will always return.
    }
    ...
 }

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    switch (indexPath.section) {
        case SECTION_MAP:
        {
            ULMapCell *cell = [tableView dequeueReusableCellWithIdentifier:@"map" forIndexPath:indexPath];
            return cell; //the cell in question is this one, so it will always return this cell.
        }
     ...
}

UPDATE: I have no problems with registering nibs. It was already working perfectly before the gesture recognizer. Please stop telling me how to register nibs for table view, I already know that as a senior iOS developer.

UPDATE 2: I confirm that it is occuring only when I add it through Interface Builder and there is no problem if I add it anywhere programmatically.

Why would this be happening?

Can Poyrazoğlu
  • 33,241
  • 48
  • 191
  • 389
  • can you post more details like adding recognizer, cellForRowAtIndexPath and didSelectRowAtIndexPath methods ? – Miknash Sep 11 '16 at 14:49
  • @NickCatib added more details. – Can Poyrazoğlu Sep 11 '16 at 14:57
  • One more thing, how did you add recognizer to the cell (before adding it in awakeFromNib) ? – Miknash Sep 11 '16 at 14:58
  • @NickCatib I added it through Interface Builder – Can Poyrazoğlu Sep 11 '16 at 14:59
  • My main concern here is that app doesn't have reference to wanted cell and hence, the crash. My advice would be to add recognizer for each cell in cell itself and through delegate, notify view controller to do stuff. Another thing unrelated to question: seems like you have 6539 lines of code in view controller, isn't that too much ? This is just suggestion, not answer :) – Miknash Sep 11 '16 at 15:06
  • You need to post the complete error message in your question. And point out which line is line 6539 of `UITableView.m`. – rmaddy Sep 11 '16 at 16:07
  • @rmaddy I want to believe that that was a joke: http://stackoverflow.com/a/4181078/811405 how on Earth can I access the implementation of `UIKit`? – Can Poyrazoğlu Sep 12 '16 at 07:19
  • Oops. Actually it was serious but I was tired and didn't notice the filename. You do still need to post the complete error though. And you need to track down which line in your code exactly is causing the error. – rmaddy Sep 12 '16 at 13:52
  • @rmaddy I've added an exception breakpoint and it breaks at `ULMapCell *cell = [tableView dequeueReusableCellWithIdentifier:@"map" forIndexPath:indexPath];` (my code) with that assertion failure in the question. I'm sure there is no other problem with the nib as it works perfectly when I remove the gesture recognizer. – Can Poyrazoğlu Sep 12 '16 at 14:02
  • You need to get the complete error from the assertion failure. You may have better luck seeing the complete error if you temporarily disable the exception breakpoint. – rmaddy Sep 12 '16 at 14:08
  • @rmaddy I don't understand what exactly you are talking about. The only exception that I'm getting is that one, the only log (other than my own NSLogs) is the line that I've posted... I don't know where else should I look. – Can Poyrazoğlu Sep 13 '16 at 06:23
  • I had exactly the same problem. Have worked around with adding the recognisers in code. The nib was fine I could instantiate a view from it but registering/dequeueing from the tableView was broken as soon as I added the recogniser. – Joseph Lord Nov 03 '16 at 16:43

3 Answers3

12

The objects in a nib are organised hierarchically. Often there is just one object at the top level: the root view (in your case that's the cell). However, nibs can contain multiple top-level objects. In fact, gesture recognizers are added to the nib as top-level objects.

Any code that loads a nib with multiple top-level objects needs to know how to deal with this. For example, the code loading the nib for a UITableViewCell could:

  1. find the cell object in the array of top-level-objects
  2. make sure there is no other cell (because it would be impractical to add a heuristic for which one to choose)
  3. ignore all top-level UIGestureRecognizers since they are retained by the views they have been added to
  4. make sure there is nothing else in the top-level objects array

Unfortunately, the way Apple chose to deal with multiple top-level objects when loading UITableViewCell and UICollectionViewCell nibs is to throw an exception. That's why we cannot add gesture recognisers to cells in Interface Builder.

nils
  • 1,786
  • 13
  • 18
0

Try this instead in you cellforrow method, case SECTION_MAP

[tableView registreNib:[UINib nibWithName@"ULMapCell" bundle:nil] forCellReuseIdentifier@"map"];

ULMapCell *cell = (ULMapCell*)[tableView dequeueReusableCellWithIdentifier:@"map"];
if(!cell){
 //alloc and init the cell
}
return cell;

And I prefer add the gesture in CustomCell itself and set a delegate method.

Hope this helps.

David Kong
  • 123
  • 1
  • 9
0

Above your error Assertion failure in -[ULFeedView _dequeueReusableViewOfType:withIdentifier:] indicates

If you use the dequeueReusableCellWithIdentifier:forIndexPath:,we must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method as Apple Document Says

So you need to add first registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: in viewDidLoad method

in viewDidLoad method add below line of code first(Use either option 1 or option 2.It is your wish)

OPTION 1:

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

OPTION 2:

[self.tableView registerNib:[UINib nibWithNibName:@"ULMapCell" bundle:nil] forCellReuseIdentifier:@"map"];

Once we registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its initWithStyle:reuseIdentifier: method. For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s prepareForReuse method instead.

Assertion failure in dequeueReusableCellWithIdentifier:forIndexPath:

Then add pinch gesture recognizer code in cellForRowAtindexPath method

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    ULMapCell *cell = (ULMapCell *)[tableView dequeueReusableCellWithIdentifier:@"map" forIndexPath:indexPath];
    // If there is no cell to reuse, create a new one
    if(cell == nil) 
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ULMapCell" owner:self options:nil];
        cell = [nib objectAtIndex:0]; //If you have lot of cell in ULMapCell give your required index according to your need
    }

    //Add pinch gesture recognizer code here
     UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
     [cell addGestureRecognizer:pinchGesture];
     return cell;
}

- (void)handlePinch:(UIGestureRecognizer *)recognizer
{
   if (recognizer.state == UIGestureRecognizerStateRecognized) {
    NSLog(@"Pinch Handled Here");
   }
 }
Community
  • 1
  • 1
user3182143
  • 9,459
  • 3
  • 32
  • 39
  • 1
    I actually have no problems registering the nib. However, adding the pinch recognizer programmatically (instead of Interface Builder) seems to work. I didn't do it in `cellFor...` but did it in `awakeFromNib` and it works. But I'd love to know why adding it in Interface Builder results in a crash though. – Can Poyrazoğlu Sep 12 '16 at 07:26