PrototypeCells Not Appearing - iphone

I am trying to write an app with a 'main page' of UIButtons that when tapped will Segue to UITableView, which will in turn Segue to another View etc. I have no errors or warnings in my code, and I thought I designed it well, but when I run the app the PrototypeCells don't even appear.
This is how I have my Storyboard set up right now (I'm sorry but I can't post images yet, as I'm a new user). The little beer mug is a UIButton that successfully performs the Segue to the UITableView window (this is the one that doesn't load the PrototypeCells).
The Brew View Controller has no code in it other than the defaulted methods.
I created a class called Brewery and gave it the following properties
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *address;
#property (nonatomic, copy) NSString *info;
#property (nonatomic, copy) NSString *brews;
I created the Brewery View Controller and added the following methods along with the default code
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.breweries count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"BreweryCell"];
Brewery *brewObject = [self.breweries objectAtIndex:indexPath.row]; //might be an error in here
cell.textLabel.text = brewObject.name;
return cell;
}
Yet when I run this, the PrototypeCells aren't even showing. The ReuseIdentifier matches both in storyboard and in the code, and the View is attached to the dataSource and the Delegate. Can anyone help me figure out what I'm doing wrong? I am also new to site, so please tell me if there is something I am doing wrong or if you need more information to assist me.

Even though you have said you have set the dataSource, if numberOfSectionsInTableView is not being called then it means the data source is not set correctly.
I suggest checking this in viewDidAppear and logging the data source and delegate, and programatically checking the equal self.
There are a few pitfalls with setting IBOutlets in interface builder.
From what you have said in your blurb:
the View is attached to the dataSource and the Delegate
This is wrong. It should be the file's owner which is the View Controller.

Related

iOS 7 UITableView indexpath row property is nil

I have a UITableView and it contains a custom UITableViewCell. To test, I have an array that has three strings in it. The UITableView delegate methods are called as expected, however, the tableView:cellForRowAtIndexPath delegate is always passed an NSIndexPath instance whose row property is always == nil:
tableView:cellForRowAtIndexPath is called 3 times (once for each object in my array). I added the tableView from within the designer (storyboard) and created an outlet for it. The UITableViewCell instances appear to be correctly instantiated which each call to this delegate. I just can't wrap my head around why the [indexPath row] value is always nil.
Interface(s):
In the implmentation file:
#interface FirstViewController ()
#property(nonatomic, strong)AppDelegate *sharedDelegate;
#property(nonatomic, strong)NSArray *userList;
#end
In the header:
#interface FirstViewController : UITableViewController <FacebookDelegate>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
Init the custom cell:
-(void)viewDidLoad
{
[self.tableView registerClass: [ListCategoryCell class]forCellReuseIdentifier:#"ListCategoryCell"];
self.userList = #[#"d", #"g", #"f"]; // make some test data
}
And the delegate this is driving me mad:
//NSIndexPath.row is nil ?!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"ListCategoryCell";
ListCategoryCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = (ListCategoryCell *)[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
cell.titleLabel.text = [self.userList objectAtIndex:[indexPath row]];
cell.detailLabel.text = #"Detail";
return cell;
}
Am I missing something? Thanks!
Working Now
I left out some context (and I should not have) that I believe was very relevant to my problem. I created a UIViewController originally and then added a UITableView to this as the view. In the UITableView I created a custom prototype cell. I did all the house work:
UIViewController implemented the UITableViewDelegate & UITableViewDatasource.
Created and outlet for the UITableView.
Hooked up all the outlets
Everything seemed to work except for the fact that indextPath.row property was always nil. Some resources I found suggested that custom cells were not visible before the uitableview delegates were called.
In the end I made my class a subclass of UITableViewController. Things started working. I am still curious why my original attempt was failing.
Thanks for everyone's time. Some great comments helped me investigate some topics that are "good to know".
You need to provide at least two methods in view controller if you want it to manage your table view. They are:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
You've already provided the second, so your table view actually can produce cells but it doesn't know how many.The default value the first method returns is nil.That is the reason why you don't even have an index path.
Optionally:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
The default value is one,so you don't need to override this in case you have only one section
Make sure your view controller also follows delegate and datasource protocols.

tableView property declaration or linkages

I have a View (SearchView) with a SearchDisplayController and a TableView
in .h:
#property (nonatomic, retain) IBOutlet UITableView *tableView;
I linked this in .xib file to the TableView: >
Then in cellforrow:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
if(listGoal){
Goal *goalz = nil;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
goalz = [self.filteredListContent objectAtIndex:indexPath.row];
cell.textLabel.text = goalz.goalNaam;
}
else
{
goalz = [arr objectAtIndex:indexPath.row];
cell.textLabel.text = goalz.goalNaam;
cell.detailTextLabel.text = goalz.goalBeschrijving;
}
}
I test if I need the filteredListContent or the original array, arr. (Because I'm using a SearchDisplayController)
Which is working.
In another method,
if (tableView == self.searchDisplayController.searchResultsTableView)
is not working anymore, so I tried using
self.tableView
but this isn't working either and
(UITableView *)tableView
isn't working either.
I know something is wrong with my property declaration or linkages, but what is wrong ?
One way you can access search view in your custom method would be keep a strong reference to your search view when you get it. But I am NOT sure whether it would be valid across multiple searches.
May be you can just have a BOOL variable set and use that in your custom method. I think you would not be able to access search view in your custom method otherwise.

Multiple TableViews in a single screen

I have a UIViewController that I plan to have two TableViews and some other items in.
Both TableViews I am using on other screens, so I want to make them as independent and reusable as possible. One of those TableViews is called messageList (A UITableView) which shows my ChatHistory.
I am trying to understand if my approach is. [Edited 9/2 with correct code to make this approach work]
One approach would be to use a single table with 2 different sections, then in the delegate methods use a conditional statement to see which section is which and act accordingly.
The problem with this approach is usability. I want to easily reuse my TableViews in other views where one or the other TableView may or may not exist. Additionally, I want the DataSource to exist throughout the lifecycle of the app regardless of what Controller is instantiated or active.
My approach is to separate the view controller that manages the table view's from the table UITableViewDataSource and UITableViewDelegate implementations. But I am having a problem making this work.
Focusing on one of the TableViews, my ChatTableView.
In my AppDelegate has a property for chatHistory of type ChatHistory which implements UITableViewDelegate & UITableViewDataSource.
// AppDelegate.h
ChatHistory *chatHistory;
...
#property (nonatomic, retain) ChatHistory *chatHistory;
// ChatHistory.h
#import <Foundation/Foundation.h>
#interface ChatHistory : NSObject <UITableViewDelegate, UITableViewDataSource> {
UITableViewCell *nibLoadedCell;
NSMutableArray *messages;
}
#property (nonatomic, retain) UITableViewCell *nibLoadedCell;
#property (nonatomic, retain) NSMutableArray *messages;
#end
// ChatHistory.m - Note this code, including the custom cell was working correctly when it was a part of the controller so I believe it should be correct
#import "ChatHistory.h"
#include "ChatMessage.h"
#implementation ChatHistory
#synthesize nibLoadedCell; // custom cell design
#synthesize messages;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [messages count];
}
- (NSString *)tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section {
return [NSString stringWithFormat:#"Discussion"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"ChatTableCell" owner:self options:nil];
cell = nibLoadedCell;
}
// custom tag order - username; message; future - Avatar; like; dislike
ChatMessage *obj = [messages objectAtIndex:indexPath.row];
UILabel *messageLabel = (UILabel *) [cell viewWithTag:1];
messageLabel.text = obj.message;
UILabel *usernameLabel = (UILabel *)[cell viewWithTag:2];
usernameLabel.text = obj.sender;
return cell;
}
- (void)dealloc {
if (messages) [messages release];
[super dealloc];
}
#end
// MyViewController.m
- (void)viewDidLoad { // MAKE SURE TO INITIALIZE viewDidLoad not InitWithNib
if (!appDelegate.chatHistory)
appDelegate.chatHistory = [[ChatHistory alloc] init];
messageList = [[UITableView alloc] initWithFrame:CGRectMake(0, 54, 320, 100) style:UITableViewStylePlain];
messageList.dataSource = appDelegate.chatHistory;
messageList.delegate = appDelegate.chatHistory;
[self.view addSubview:messageList];
...
You do not need to make a view controller your tableview DataSource or delegate; any object can be set. You can use a singleton as Felix suggests, or any other class structure you want. Since you mention that you want the chat history to be available from anywhere in the app, it makes sense to provide a UITableViewDataSource protocol to that chat history.
As for the UITableViewDelegate, you can simply create a new class as a subclass of NSObject and implement the delegate there. Make sure it's created and retained properly, and set in (upon load) as the delegate for your table views.
If you want one central data store, you could create a Singleton class with the data.
Then set it as the data source for the table view or fetch the array (or whatever you got) from the data store in your UIViewController / UITableViewController.
If you initialize the data store in your AppDelegate, you can access it from every class you want (note that all data you load, will remain in memory until your application gets terminated by iOS)
How to create a Singleton class in Objective-C
I would do it this way: make the two UITableViews subviews of one view controller.
In each of the datasource methods you simply distinguish between the two tables, similar to the code Apple provides in the UISearchDisplayController examples. For instance:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == myTableView1) {
// return appropriate number of rows
}
// return appropriate number of rows for the other table view
}
I know this does not separate the two table view classes very neatly. You would have to have a view controller controlling two other view controllers, one for each tableview.
Perhaps one has to consider the tradeoff between reusability and the complications of a more convoluted architecture (which typically also leads to classes that do not perform all that well in terms of reusability). That's why I would recommend the approach from the Apple sample projects.

Are there Anyone that use TableViewController without subclassing?

I am just curious. In IB, we can put a tableviewcontroller. However, as far as I know, we always subclass that tableview controller right? That way we can implement delegate, etc.
However, it seems that for some "default" behavior, IPhone intended tableviewcontroller to be used as is. Otherwise, why would IB let us put tableViewController like that?
Are there any sample code where people use tableViewController without subclassing?
Where does they implement things like what cells to draw, etc. then?
I guess the right answer of the question is that it's simply ridiculous to use a UITableViewController without sub classing. No body is doing it. Please correct me if I am wrong. I am just curious.
Whether you use a subclass of UITableViewController or UIViewController you need to set the data your table is going to display, otherwise, what's the point of a blank table? To achieve that you have to subclass and implement some methods. It's also a good idea to keep the delegate and the datasource in the same controller, unless the complexity really asks for different classes.
That being said, I always create my own table controllers as a subclass of UIViewController and implement the table controllers methods myself, because it gives you more flexibility. Matt Gallagher has several posts on how and why. See UITableView construction, drawing and management (revisited).
If you want to give it a try, create a subclass of UIViewController with a XIB and add the following sample code:
// interface
#import <UIKit/UIKit.h>
#interface SettingsVC : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#property (nonatomic, retain) NSMutableArray *array;
#end
// implementation
#synthesize tableView = _tableView;
#synthesize array = _array;
# pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.array count];
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
int row = [indexPath row];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [self.array objectAtIndex:row];
return cell;
}
Then add a UITableView object to the XIB, link the tableView of the controller to the UITableView object, and link the delegate and datasource of the UITableView to the controller.
No, this is not necessary to inherit your class with tableViewController. You can use table view by simply
putting TableViewController in xib.
and setting its delegate and datasourse to file's owner you can draw the table cells.
I don't think you can use a UITableViewController as is, it's like using a UIViewController without subclassing it : you can't set any inner mechanics.
But you can have a UITableView without using a UITableViewController.
Sure you can use UITableViewController without subclassing it.
Samplecode is very easy and straight forward.
For example like this:
- (IBAction)selectSomeOption:(id)sender {
UITableViewController *tableViewController = [[UITableViewController alloc] initWithStyle:UITableViewStyleGrouped];
tableViewController.tableView.dataSource = self;
tableViewController.tableView.delegate = self;
tableViewController.title = "Select some option";
[self.navigationController pushViewController:tableViewController animated:YES];
}
and the UITableViewDatasource and Delegate methods go into the same class.
Sure, if you like pain you could create a UIViewController in code and add a tableView on your own.
Or create a subclass for such an easy task.
The use of a non subclassed UITableViewController is sometimes convenient.

UITableViewCell outlets not set during bundle load (possibly very elementary question)

What are the most common reasons for an outlet (a class property) not being set during a bundle load?
I'm sorry; most likely I'm not using the correct terms. It's my first steps with iPhone OS development and Objective-C, so please bear with me. Here is more details. Basically, I'm trying to create a table view based form with a fixed number of static rows. I followed this example:
http://developer.apple.com/iphone/library/documentation/userexperience/conceptual/TableView_iPhone/TableViewCells/TableViewCells.html
Scroll down to The Technique for Static Row Content please. I have one nib file with one table view, three table cells and all connections set as in the example. The problem is that the corresponding cell properties in my controller are never initialised. I get an exception in cellForRowAtIndexPath complaining that the returned cell is nil: UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath.
Here are the relevant parts from the implementation of the controller:
#synthesize cellA;
#synthesize cellB;
#synthesize cellC;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row)
{
case 0: return cellA; break;
case 1: return cellB; break;
case 2: return cellC; break;
default: return nil;
}
}
And here is the interface part:
#interface AssociatePhoneViewController : UITableViewController
{
UITableViewCell *cellA;
UITableViewCell *cellB;
UITableViewCell *cellB;
}
#property (nonatomic, retain) IBOutlet UITableViewCell *cellA;
#property (nonatomic, retain) IBOutlet UITableViewCell *cellB;
#property (nonatomic, retain) IBOutlet UITableViewCell *cellC;
#end
This must be possibly one of the the most embarrassing questions on StackOverflow. It looks like the most basic example code.
Is is possible that the cells are not instantiated with the nib file? I have them on the same level before the tabula view in the nib file. I tried to move them after the table view, but it did not make any difference.
Are table cells in some way special? Do I need to set some flag or some property on them in the nib file? I was under the impression that all classes (views, windows, controllers …) listed in a nib file are simply instantiated (and linked using the provided connections).
Could it possibly be some memory issue? The cell properties in my controller are not defined in any special way.
I found out what the problem was already some time ago, and I should have posted it earlier ... sorry. Here it goes.
The culprit was the Interface Builder - or perhaps me not using it correctly. I drag-dropped my view controller into a different nib file, and somehow managed to delete (or not fill) the NIB Name field. Either way, the view controller was instantiated without its NIB file.
try instantiating (alloc init) the cells in viewDidLoad