2

I am having a ton of trouble trying to get a table view to work on my iPhone. The weird thing is that it seems to work completely fine on my iOS simulator (i.e., I can add an entry to an array, and that entry shows up in my table view). However, when I try to add an entry when using my iOS device, the codes breaks on the line dequeueReusableCellWithIdentifier:. I've checked for capitalization inconsistencies, name inconsistencies, have reimplemented prepareForReuse in the custom UITableViewCell subclass, have tried defining fields in my UITableViewCell subclass using IBOutlets v. tags, and perhaps a few more things but none have worked.

This questions is tangentially related to my previous question: Debugging strategies when UITableView's cells don't load?

The tough part about programming is always knowing which question to ask, so I apologize if it turns out I am asking the wrong questions.

UPDATE 6: Problem Is Custom Layout For UITableViewCell On iOS 5

I tested using a subclass of UITableViewCell and UITableViewCell with a custom layout. Using a subclass of UITableViewCell with style UITableViewCellStyleDefault does work on both iOS 5 and iOS 6 iPhone simulator. However, using a generic UITableViewCell with a custom style crashes on iOS 5 but not iOS 6. Interestingly, I don't see a declaration for a custom UITableViewCellStyle in the documentation for UITableViewCell...

UPDATE 5: iOS 5 v. 6 + Custom UITableViewCell Subclass?

Hello: Continued testing today and it appears that it is an issue between how iOS 5 and 6 treat custom UITableViewCell subclasses. No solution yet :(

UPDATE 4: iOS 5 v. iOS 6?

So all I've been able to notice is that this seems to be an issue with iOS 5 versus iOS 6. When testing on iOS 6 using line GlassboxCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier] the code below works. However, neither that line nor GlassboxCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath] work in iOS 5. Any ideas? I somehow got it to work exactly once by changing the identifier to protocell.

UPDATE 3: I now use GitHub!

Here is the relevant repo: https://github.com/kenmhaggerty/Glassbox

UPDATE 2: More Observations

So I had added in @synthesize tableView = _tableView because I read in a response somewhere that it might help, but I now realize that it stopped my data from loading in my table view even when running on the iOS simulator. Commenting out that line of code returns the code back to how I describe it above: it works just fine on the iOS simulator but breaks on line dequeueReusableCellWithIdentifier: with no specified error, just Thread 1: breakpoint 1.1.

UPDATE 1: Relevant Code

GlassboxTableViewController.h

//
//  GlassboxTableViewController.h
//  Glassbox
//
//  Created by Ken M. Haggerty on 10/22/12.
//  Copyright (c) 2012 Ken M. Haggerty. All rights reserved.
//

#pragma mark - // NOTES (Public) //

#pragma mark - // IMPORTS (Public) //

#import <UIKit/UIKit.h>

#pragma mark - // PROTOCOLS //

//@protocol GlassboxTableViewDatasource <NSObject>
//@property (nonatomic, weak) NSMutableArray *arrayOfPlayers;
//@end

#pragma mark - // DEFINITIONS (Public) //

@interface GlassboxTableViewController : UITableViewController
@property (nonatomic, strong) NSMutableArray *arrayOfPlayers;
- (IBAction)addPlayer:(UIBarButtonItem *)sender;
//@property (nonatomic, strong) id <GlassboxTableViewDatasource> datasource;
@end

GlassboxTableViewController.m

//
//  GlassboxTableViewController.m
//  Glassbox
//
//  Created by Ken M. Haggerty on 10/22/12.
//  Copyright (c) 2012 Ken M. Haggerty. All rights reserved.
//

#pragma mark - // NOTES (Private) //

#pragma mark - // IMPORTS (Private) //

#import "GlassboxTableViewController.h"
#import "GlassboxCell.h"
#import "Player.h"
#import <MobileCoreServices/MobileCoreServices.h>

#pragma mark - // DEFINITIONS (Private) //

#define SIDEBAR_WIDTH_PERCENT 0.75

@interface GlassboxTableViewController () <UITableViewDataSource, UITableViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
//@property (nonatomic, weak) IBOutlet UITableView *tableView;
- (void)setup;
@end

@implementation GlassboxTableViewController

#pragma mark - // SETTERS AND GETTERS //

@synthesize arrayOfPlayers = _arrayOfPlayers;
@synthesize tableView = _tableView;
//@synthesize datasource = _datasource;

- (void)setArrayOfPlayers:(NSMutableArray *)arrayOfPlayers
{
    _arrayOfPlayers = arrayOfPlayers;
}

- (NSMutableArray *)arrayOfPlayers
{
    if (!_arrayOfPlayers) _arrayOfPlayers = [[NSMutableArray alloc] init];
//    [_arrayOfPlayers addObject:[[Player alloc] initWithUsername:@"Ken H.:"]];
    return _arrayOfPlayers;
}

#pragma mark - // INITS AND LOADS //

- (void)setup
{
    self.tableView.dataSource = self;
    self.tableView.delegate = self;
}

- (id)initWithStyle:(UITableViewStyle)style
{
    NSLog(@"[initWithStyle]");
    self = [super initWithStyle:style];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)viewDidLoad
{
    NSLog(@"[viewDidLoad]");
    [super viewDidLoad];
    [self setup];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}

//- (void)viewDidAppear:(BOOL)animated
//{
//    [super viewDidAppear:animated];
//    [self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width*SIDEBAR_WIDTH_PERCENT, self.view.frame.size.height)];
//}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - // PUBLIC FUNCTIONS //

- (IBAction)addPlayer:(UIBarButtonItem *)sender
{
    [self alertAddPlayer];
}

#pragma mark - // PRIVATE FUNCTIONS //

- (void)alertAddPlayer
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Add New Player" message:@"Please type player name:" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK",nil];
    alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    alert.tag = 1;
    [alert show];
}

- (void)alertInvalidPlayer
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Invalid Name" message:@"Please type another name:" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK",nil];
    alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    alert.tag = 1;
    [alert show];
}

- (void)alertAddPhoto
{
    NSLog(@"[TEST] alertAddPhoto");
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
    {
        NSArray *mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
        if ([mediaTypes containsObject:(NSString *)kUTTypeImage])
        {
            UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
            imagePickerController.delegate = self;
            imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
            imagePickerController.allowsEditing = YES;
//            imagePickerController.cameraDevice = UIImagePickerControllerCameraDeviceFront;
//            imagePickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
            imagePickerController.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeImage];
//            [self presentViewController:imagePickerController animated:YES completion:nil];
        imagePickerController.cameraDevice = UIImagePickerControllerCameraDeviceFront;
            [self presentModalViewController:imagePickerController animated:YES];
            return;
        }
    }
    NSLog(@"[TEST] No camera available");
    [self.tableView reloadData];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
    if (!image) image = [info objectForKey:UIImagePickerControllerOriginalImage];
    if (image)
    {
        [[self.arrayOfPlayers lastObject] setPhoto:[[UIImageView alloc] initWithImage:image]];
    }
    [self dismissImagePicker];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
    [self dismissImagePicker];
}

- (void)dismissImagePicker
{
//    [self dismissViewControllerAnimated:YES completion:^{
//        [self.tableView reloadData];
//    }];
    [self dismissModalViewControllerAnimated:YES];
    [self.tableView reloadData];
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 0) NSLog(@"Cancel tapped");
    else
    {
        if (alertView.tag == 1)
        {
            if (buttonIndex == 1)
            {
                if ([[[alertView textFieldAtIndex:0] text] length] != 0)
                {
                    [self.arrayOfPlayers addObject:[[Player alloc] initWithUsername:[[alertView textFieldAtIndex:0] text]]];
                    [self alertAddPhoto];
                }
                else [self alertInvalidPlayer];
            }
        }
    }
}

#pragma mark - // PRIVATE FUNCTIONS (Miscellaneous) //

// TableView data source //

//- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
//{
//#warning Potentially incomplete method implementation.
//    // Return the number of sections.
//    return 0;
//}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//    return self.datasource.arrayOfPlayers.count;
    return self.arrayOfPlayers.count;
}

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

    cell.name.text = [[self.arrayOfPlayers objectAtIndex:indexPath.row] username];
    cell.action.text = @"LOADED SUCCESSFULLY";
    cell.time.text = @"Just now";
    cell.photo = [[self.arrayOfPlayers objectAtIndex:indexPath.row] photo];

//    [((UILabel *)[cell viewWithTag:1]) setText:[[self.arrayOfPlayers objectAtIndex:indexPath.row] username]];
//    [((UILabel *)[cell viewWithTag:2]) setText:@"has been added."];
//    [((UILabel *)[cell viewWithTag:3]) setText:@"Just now"];
//    [((UIImageView *)[cell viewWithTag:4]) setImage:[[[self.arrayOfPlayers objectAtIndex:indexPath.row] photo] image]];

    [cell.contentView setFrame:CGRectMake(cell.contentView.frame.origin.x, cell.contentView.frame.origin.y, cell.contentView.frame.size.width, 120)];

    return cell;
}

/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the specified item to be editable.
    return YES;
}
*/

/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    }   
    else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }   
}
*/

/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/

/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the item to be re-orderable.
    return YES;
}
*/

// TableView delegate //

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Navigation logic may go here. Create and push another view controller.
    /*
     <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
     // ...
     // Pass the selected object to the new view controller.
     [self.navigationController pushViewController:detailViewController animated:YES];
     */
}

@end

Let me know if I should post more.

Community
  • 1
  • 1
Ken M. Haggerty
  • 24,902
  • 5
  • 28
  • 37
  • It's a half-baked non-answer but if you've changed or renamed the storyboard it _might_ be worth deleting the app from your device and reinstalling it. – jrturton Oct 25 '12 at 06:06
  • Still breaks. Nice try though...I had problem previously where the solution was that I had to retype a line of code character-by-character, so I wouldn't have been surprised. – Ken M. Haggerty Oct 25 '12 at 06:11
  • Have you tried to switch Autolayout off (see my answer)? – Martin R Nov 13 '12 at 17:37

4 Answers4

2

(Your github project does not compile (Player.h/Player.m missing), so it is difficult to reproduce the issue.)

But I noticed that "Use Autolayout" is on in the MainStoryboard file. Autolayout works only on iOS 6 and later, not on iOS 5!

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Indeed! The actual phrasing for this option when it comes to UITableViewCells is "Autoresize subviews". Unchecking this made it work :) – Ken M. Haggerty Nov 17 '12 at 10:21
0

Please post your code. I can advice you to leave the xib files for uitableviewcell and try again. Do you use one kind of cell? or you use few different style?

===== ANSWER =====

When you create cell GlassboxCell *cell and use dequeueReusableCellWIthIdentifier you need check if cell is allocated.

// use dequeueReusableCellWithIdentifier for init cell
if (cell == nil){
    cell = [[[GlassboxCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:yourIdentifier]] autorelease];
}
//rest your code for init properties for cell
  • Added. I am using one kind of custom UITableViewCell subclass. – Ken M. Haggerty Oct 25 '12 at 01:51
  • My post edited, please init cell in appropriate way, if you use xib or another init method. Cheers – Jacek Grygiel Oct 25 '12 at 05:09
  • Didn't work. Also, needing to check `if (cell == nil)` is deprecated in iOS 5 and later, cf.: http://stackoverflow.com/questions/11042129/uitableviewcell-allocation-issue-cell-is-not-nil – Ken M. Haggerty Oct 25 '12 at 05:50
  • Yep but only if you use storyboard, have you tried to use standard UITableViewCell instead of yours, just for checking, i don't have your code so it is hard to check all things :) – Jacek Grygiel Oct 25 '12 at 05:55
  • I am using a storyboard! Sorry if that was not clear. I have a prototype cell of class `GlassboxCell` laid out in my storyboard with identifier `New Cell`. It contains three UILabels and a UIImageView. – Ken M. Haggerty Oct 25 '12 at 05:56
  • Try with standard class UITableViewCell, heh storyboard is not a good tool for start, i prefer to use only code without xib's and storyboard, in huge project it usually makes complication – Jacek Grygiel Oct 25 '12 at 06:09
  • Still breaks at same line and only for iOS device. :-( – Ken M. Haggerty Oct 25 '12 at 06:16
  • do you have these code on github or any repository? and can you share me? – Jacek Grygiel Oct 25 '12 at 06:21
  • Just downloaded GitHub and am super confused as to how to push my already-created repository to the web... :S I don't see any tutorials on iTunes U re: how to use GitHub. – Ken M. Haggerty Oct 25 '12 at 06:36
  • if you want, you can also zip whole project and upload to any service, just to share for a while;) – Jacek Grygiel Oct 25 '12 at 06:41
  • Hoorah! I learn quickly I suppose. I just needed to download Command Line Tools via Xcode and mirror via Terminal. – Ken M. Haggerty Oct 25 '12 at 07:03
0

ok man try to use this function instead of yours.

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

    if (cell == nil)
    {
        cell = [[GlassboxCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

    }

    cell.name.text = [[self.arrayOfPlayers objectAtIndex:indexPath.row] username];
    cell.action.text = @"LOADED SUCCESSFULLY";
    cell.time.text = @"Just now";
    cell.photo = [[self.arrayOfPlayers objectAtIndex:indexPath.row] photo];

    [cell.contentView setFrame:CGRectMake(cell.contentView.frame.origin.x, cell.contentView.frame.origin.y, cell.contentView.frame.size.width, 120)];

    return cell;
}
0

I think I found the problem...at least it works on my project.

When you make a UITableViewController class with an older version of Xcode (say 4), the generated code for cellForRowAtIndexPath is this:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

But when you make a UITableViewController with Xcode 4.5.2 (mine), the generated code for cellForRowAtIndexPath is this:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

So in my case all I did was remove the "forIndexPath:indexPath" portion and it works!

(This is my first answer ever so please be gentle if I screwed up something)

TooManyEduardos
  • 4,206
  • 7
  • 35
  • 66