Ichigo Kurosaki Ichigo Kurosaki - 1 month ago 13
iOS Question

All UITableCells dissappear when tapping on UITableView in iOS 7

I am having a problem with my UITableView in iOS7. Initially, the data loads in just fine, and I get output in my console that proves that the cells are speaking to the data source correctly, but as soon as I tap anywhere on the table, the cells disappear and the table goes blank. The height of the cells in the empty UITableView seem to be honoring the height my custom prototype cell (410px), but all the data in the cells vanish, and the empty table view acts like it only has one cell in it (like its default state before it gets hooked up to the delegate).

I am using Storyboards for this app.

To get a little context, this app is similar to the iphone Instagram app, and I am using this application as way to learn iOS 7 development. I have been banging my head up against a wall trying to solve this issue, and I can't find any online resources that can help me solve this, so I wanted to ask all the smart peeps on Stack Overflow.

I have prepared a graphic that helps you see the problem

a graphic that helps demonstrate the problem
higher resolution version here

Here is my TableViewController code:

@interface PA_PhotoTableViewController ()

@property (nonatomic, copy) NSArray *photos;

@end



@implementation PA_PhotoTableViewController


- (void)viewDidLoad {
[super viewDidLoad];
self.photos = [[PA_PhotoStore sharedPhotoStore] allPhotos];
}


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[[PA_PhotoStore sharedPhotoStore] allPhotos] count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
PA_PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PhotoCell" forIndexPath:indexPath];


PA_Photo *photo = (self.photos)[indexPath.row];

cell.photoTitle.text = photo.title;
cell.photoOwnerName.text = [NSString stringWithFormat:@"%@", photo.owner];
cell.photoLikes.text = @"99";

// Photo Image URL
NSURL *photoImageURL = [NSURL URLWithString:photo.image_full_url];
[cell.photoImage sd_setImageWithURL:photoImageURL placeholderImage:[UIImage imageNamed:@"lightGraySpinningLoader.gif"]];

// Photo Owner Image
[cell.photoOwnerImage sd_setImageWithURL:photoImageURL placeholderImage:[UIImage imageNamed:@"lightGraySpinningLoader.gif"]];


return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

// This code never gets called when I try to tap on a cell
NSLog(@"A row was selected");
}


- (void)dealloc {
NSLog(@"dealloc called in PA_PhotoTableViewController");
}


and here is the custom cell code PA_PhotoCell (consolidated .h & .m files):

@interface PA_PhotoCell : UITableViewCell

@property (nonatomic, weak) IBOutlet UIImageView *photoImage;
@property (nonatomic, weak) IBOutlet UILabel *photoTitle;
@property (nonatomic, weak) IBOutlet UILabel *photoOwnerName;
@property (nonatomic, weak) IBOutlet UIImageView *photoOwnerImage;
@property (nonatomic, weak) IBOutlet UILabel *photoLikes;
@property (nonatomic, weak) IBOutlet UILabel *photoTimestamp;
@property (nonatomic, weak) IBOutlet UILabel *photoComments;

@end



@implementation PA_PhotoCell

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
NSLog(@"in set selected");
}


-(void)setHighlighted:(BOOL)highlighted {
NSLog(@"in set highlighted");
}


You can see a few
NSLog()
calls to help me see if anything is getting called.

Can anyone help me see where I am going wrong? The end goal is to click on one of the TableViewCell instances and launch a UINavigationController, I know how to do that, but I can't move on to that step until I figure out why my UITableView wont scroll, and why it disappears when I click on it! Please help!

Thanks in advance for anyone who can help with this!

EDIT: After much testing, debugging and experimentation, I have been able to conclude that the problem is actually not with the UITableView at all, and it is, in fact, a problem with how the UITableView is being loaded into it's parent view. I still haven't found a solution to my problem, but I am getting closer to finding the cause. Here is what I have discovered:

First, when any of the UIButtons at the bottom of the screen are tapped (see photo reference), it loads the relevant instance of UIViewController into a UIView called placeholderView. When I run my problematic UITableView OUTSIDE of this UIView (where the UITableViewController is acting on its own, not embedded within another UIView) then the table works perfectly, it scrolls, it revives click events, and so on. So as soon as I load the UITableView into the UIView, the UITableView becomes unresponsive (it doesn't scroll or receive tap events) and any attempt to interact with it, the UITableView goes completely blank. My debugging session concludes that the NSArray *photos never gets reset to nil, or manipulated in anyway, the table just goes blank.

So does anyone have any ideas on what would cause a UITableView to do this when being loaded into a generic UIView? All the other views that get loaded into this generic UIView are responsive, and behave as expected. Its just this UITableView that is giving me problems.

If you review the graphic I attached to this post (above), you will see that I am using what appears to be a UITabBarView, but it is, in fact, just a generic view with UIButtons inside. The reason I decided to craft my own "UITabBarView look-alike" instead of using the ready-made UITAbBarView class was because I wanted to give custom functionality to the "menu" button on the bottom left (I want a nice UIView to slide in from the left, and stop about 60 pixels from the right of the screen when the "menu" button is tapped, and I can't figure out how to customize the behavior of the UITabBarView, so I opted for this approach.

Here is the code that is actually loading the UITableViewController into the subview (via a CustomStoryboardSegway):

// PA_HomeViewCustomStoryboardSegue.m

#import "PA_HomeViewCustomStoryboardSegue.h"
#import "PA_HomeViewController.h"

@implementation PA_HomeViewCustomStoryboardSegue

// to create a custom segue, you have to override the perform method
-(void)perform {

// get the source and destination view controllers
PA_HomeViewController *segueSourceController = (PA_HomeViewController *)[self sourceViewController];
UIViewController *destinationController = (UIViewController *)[self destinationViewController];

for (UIView *view in segueSourceController.placeholderView.subviews){
[view removeFromSuperview];
}

segueSourceController.currentViewController = destinationController;
[segueSourceController.placeholderView addSubview:destinationController.view];

}

@end


and here is the header file for my PA_HomeViewController (the view the contains the "placeholderView" which is the target view that loads the various UIViewControllers after the user has tapped the UIButtons at the bottom of the view (similar to a TabBarView) :

@interface PA_HomeViewController : UIViewController

@property (weak, nonatomic) IBOutlet UIView *placeholderView;
@property (weak, nonatomic) UIViewController *currentViewController;

@end


I am hoping that I am just missing something obvious in the way that I am loading the UITableView into the placeholderView, and something in there is causing the UITableView to go completely blank.

I really appreciate all the advice everyone has offered so far. I am really anxious to find the cause of this problem so I can sleep at night. haha.

Answer

When you display the UITableView in a different view, you must always make sure that the view controller which "hosts" the UITableView has a strong reference to its controller. In your case, the data source for the UITableView seems to be deallocated after adding the UITableView as subview.

Changing the currentViewController property from weak to strong should fix your problem.

Comments