Im making a project for school and I'm having trouble with table view controllers, i want to add a button to link it to another page thats really it, So i have a list of 7 table cells which connect to the detail view controller, from there i want to add a button which would link that to another page but each of the 7 table cells need to go to different pages, sorry I'm not very good at explaining things but if any one can help me it would be really appreciated.
TableViewController.m
#import "tableViewController.h"
#import "TableCell.h"
#import "DetailViewController.h"
#interface tableViewController ()
#end
#implementation tableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// 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;
_Title =#[#"Centrum Advance", #"Elite Whey Protein", #"USP LABS Jack3d", #"NitroCore 24", #"PHD Synergy ISO 7", #"REFLEX One Stop", #"MET-Rx G.C.M.O"];
_Images=#[#"1C.jpg",#"2C.jpg",#"3C.jpg",#"4C.jpg",#"5C.jpg",#"6C.jpg",#"mets.jpg",];
_Review=#[#"Not Reviewed",#"'I'm a big fan of whey protein becasue the dosing is simple, easy to consume, and usually a lot cheaper than pills. I use to use the regular old GNC 100% whey protein which was good to take after a workout, but I really wanted more from my supplements. Proto Whey had a lot of great reviews and I have to say, it worked pretty well for me.'",#"'Wow. This stuff is amazing. No fillers, the taste (lemon-lime) isn't overwhelming, and I can work out solid for 1.5 hours and still feel like a beast. I've taken NO-Xplode and Black Powder, and I find that Jack3d provides more energy, while something like Black Powder gives me more pump. This is why I mix a scoop of Black Powder and a scoop of Jack3d and get totally effed at the gym.I've come to notice that if I take jack3d later in the day, it really messes with my sleep, and I contribute that to the DMAA in it, which is a stimulant. I just finished a bottle and I notice my tolerance was going up. On days that I was taking just jack3d, since I like to mix it up, I moved up to 2 scoops towards the end of the bottle. So all in all, awesome for energy in the gym, only somewhat decent regarding pump. But I still give it a solid 9. I have yet to try out 1.M.R, which I will be getting next week, and can find out then which is better for me.BTW I didn't get a 'crash' that so many people speak of, this could be that maybe I am not just prone to the type of thing, and that I work out after I get off work, so 'crashing' really doesn't matter for me.'",#"Not Reviewed",#"'I had the double chocolate flavor and it was the BEST tasting stuff I've ever had. It was so good, sometimes I just took a serviing for breakfast if I was running short on time. The effectiveness was good too, and after finishing a tub of it, I noticed just about all of my lifts increased. I gained some great vascularity in my bi's, and my chest strength exploded. Honestly, for all of you who want to spend a little money and get a nice supplement...this is your winner. I am definitely gonna use this for a while until I get sick of the taste or see a new up-and-coming product. Only reason I give value a 5 is because I paid about $40 for the 2LB tub back in January.'",#"Not Reviewed",#"Not Reviewed",];
_Size=#[#"1.2KG",#"3KG",#"2.7KG",#"3.9KG",#"5KG",#"6.4KG",#"0.5KG",];
_Does=#[#"The perfect whey protein to aid weight loss or pack on lean muscle mass",#"Add some serious muscle to your body without the fat!",#"24g of protein per scoop for just 112 calories and no sugars!",#"Premium Whey Isolate",#"Minimal carbohydrates and fats",#"The Only Way To Enjoy Whey Protein",#"27g of protein with each serving",];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (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 _Title.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TableCell";
TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
int row = [indexPath row];
cell.TitleLabel.text = _Title[row];
cell.ThumbImage.image = [UIImage imageNamed:_Images[row]];
cell.Review1.text = _Review[row];
cell.Size1.text = _Size[row];
cell.Does1.text = _Does[row];
return cell;
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"ShowDetails"]) {
DetailViewController *detailviewcontroller = [segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
int row = [myIndexPath row];
detailviewcontroller.DetailModal = #[_Title[row],_Images[row]];
}
}
#end
DetailViewController.m
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_TitleLabel.text = _DetailModal[0];
_ThumbImage.image = [UIImage imageNamed:_DetailModal [1]];
self.navigationItem.title = _DetailModal[0];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
the table cell.m is empty and the .h is used for the IBOutlets
Create a public #property on the DetailViewController that you can set in prepareForSegue:sender: TableViewController to setup the button's target in each individual DetailViewController.
// DetailViewController.h
#interface DetailViewController
#property NSInteger nextPageId; // or whatever
// TableViewController.m
// prepareForSegue...
detailviewcontroller.nextPageId = myIndexPath.row; // something like this
// DetailViewController.m
// viewDidLoad...
[myButton addTarget:self action:#selector(myButtonHandlerMethod) forControlEvents:UIControlEventTouchUpInside];
-(void)myButtonHandlerMethod {
// code to present the next "page" based on self.nextPageId
}
The method addTarget:action:forControlEvents: sets up another method myButtonHandlerMethod to be called when the user taps the button. If the UIButton is in the DetailViewController Storyboard then create a IBOutlet property and reference the button as self.myButton.
Related
I have a UITableView inside of a View. I've dragged the size of the UITableView to only displays 4 rows at a time. In the ViewController code that loads data into that UITableView, I've generated 6 items to load into the UITableView, because I wanted to verify that it would scroll.
However, when I run the program and preview it in iOS Simulator, it is not scrolling. I have checked that scrolling is enabled (Screenshot).
Here is the code in which the UITableView is populated:
#import "APFacebookFriendsViewController.h"
#interface APFacebookFriendsViewController ()
#end
#implementation APFacebookFriendsViewController
#synthesize facebookFriendsTableView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// set View title
self.title = #"Facebook Friends";
// load Facebook friends
self.facebookFriends = [self getFacebookFriends:#"Test Facebook User"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (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.facebookFriends count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CellIdentifier";
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];
UITableViewCell *cell = [self.facebookFriendsTableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// Configure the cell
NSString *facebookFriend = [self.facebookFriends objectAtIndex:[indexPath row]];
[cell.textLabel setText:facebookFriend];
return cell;
}
- (NSMutableArray *)getFacebookFriends:(NSString *)facebookUser
{
// placeholder data
NSMutableArray *facebookFriendsArray = [NSMutableArray array];
[facebookFriendsArray addObject:#"Friend A"];
[facebookFriendsArray addObject:#"Friend B"];
[facebookFriendsArray addObject:#"Friend C"];
[facebookFriendsArray addObject:#"Friend D"];
[facebookFriendsArray addObject:#"Friend E"];
[facebookFriendsArray addObject:#"Friend F"];
// END placeholder code
return facebookFriendsArray;
}
#end
It's pretty hard to tell what you're doing wrong without looking at your whole project. A few things that you might want to try:
Make sure that the table view is on the top of the other views
Check that table view's userInteractionEnabled is set to true.
Make sure that the table view's delegate and data source points to your view controller.
Try to make the table view full size and see if it's still not scrolling. If so, probably you didn't set one of the table view properties right. You can try to remove and re add the table view.
There are many more things that can go wrong, and as I said it's pretty hard to tell without seeing your project.
1.Check Your table view, and its superviews, has userInteractionEnabled set to TRUE.
2.The custom view that the table view is inside is smaller than the table view with clipsToBounds=NO, a subview that beyond the bounds of its parentview and its not interacted with. so set to clipsToBounds YES.
Insert this into viewDidLoad;
table.delegate=self;
table.datasource=self;
PRESENTATION
Mine is a simple project: It consists of a NavigationController, ViewController, and a “Search Bar and Search Display Controller”
My .h file is
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UISearchDisplayDelegate, UITableViewDataSource, UITableViewDelegate>
#end
and my .m file is
#import "ViewController.h"
#interface ViewController ()
#property(nonatomic,strong)NSMutableArray *data;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
self.data=[[NSMutableArray alloc]init];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [_data count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Configure the cell.
cell.textLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"Row %d: %#", indexPath.row, [_data objectAtIndex:indexPath.row]];
return cell;
}
#pragma mark - delegate
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(mockSearch:) userInfo:searchString repeats:NO];
return NO;
}
- (void)mockSearch:(NSTimer*)timer
{
[_data removeAllObjects];
int count = 1 + random() % 20;
for (int i = 0; i < count; i++) {
[_data addObject:timer.userInfo];
}
[self.searchDisplayController.searchResultsTableView reloadData];
}
#end
And that’s the entire program. What does it do? User makes a search and the data is displayed in a TableView (similar to a google search).
PROBLEM
I need to use a CustomTableViewCell for my table. And I need to build the TableViewCell from the storyboard (easy to visualize). I am stuck with the storyboard part. How do I place a TableViewCell on the storyboard without a TableView to place it in? I had an idea, I tried it, but it didn’t work. Here is what I did. I placed a “never-to-be-used” TableViewController in the storyboard whose sole purpose is to hold my CustomTableViewCell. Then in code I subclass TableViewCell and use IBOutlet to link the sub-views of the storyboard TableViewCell to my CustomTableViewCell . And then I used my cell as CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];. This didn’t work. The tableView remained blank. And my guess for the failure is that CustomTableViewCell does not belong to the tableView being dequeued from.
I need the UISearchBar to always stay inside the NavigationBar. But so far self.searchDisplayController.displaysSearchBarInNavigationBar = YES; is not doing it. When I first start the app the searchBar is inside the NavigationBar. But as soon as I click on it, it smacks itself right in the middle of my scene/screen and never leaves.
I need to add a Header to my TableView. Which I thought of doing the same way as the CustomTableViewCell, but with a UIView parent class. But again, the CustomTableViewCell portion failed.
PLEA
Thank you for any help you can provide me.
UPDATE
All I am trying to do is allow my users to launch a server side search and view the results in a tableView. This is such a basic thing, I image many people here have done this a number of times. Being new to iOS, I am stuck. But at this point, I have posted my entire project (anyone can reconstruct it), and I have explained in details all the ways I tried to solve the problem. So if someone has a sample project they don’t mind sharing, it would help very much. Or if you know of a git project please put a link to it. Thanks.
If you want to make a stand-alone view (not in a view controller) in IB, then you should do it in a xib file, not a storyboard. You can have as many storyboard and xib files in an app as you want; they can be mixed freely. To make a new cell in a xib file, just go to New File --> User Interface --> Empty then drag in a UITableViewCell. Add any subviews you want, and in your table view controller (or whatever class is your table view data source), register the xib file with, registerNib:forIdentifier: (usually, you do this in viewDidLoad).
I've got two views, each of which contains a tableview. They are identical in every respect except the height. They are each fed data from the same entity (currently filled with gibberish) in my Core Data store.
One of them works perfectly when scrolled, the other behaves differently. The problem is that the cells scroll past the top section header. Succeeding section titles bump older ones up as expected, and the header title slides up along with the cells.
Here are a couple of screenshots that I hope will illustrate the issue:
First, the one that works properly:
"A" is the top section header, and the cells don't scroll past it.
The next two shots are of the tableview that's behaving weirdly. I've added some arrows to show what's happening:
I've compared the settings in the Attributes Inspector, and unless I've overlooked something, they appear identical.
Anyone have any ideas?
Thanks!
Edit:
Here's the code from the associated UIViewController which is the delegate and the datasource for the TableView:
//
// AvsAViewController.m
// WMDGx
//
// Created by Tim Jones on 2/6/14.
// Copyright (c) 2014 TDJ. All rights reserved.
//
#import "AvsAViewController.h"
#interface AvsAViewController ()
{
NSFetchedResultsController *frc;
}
#end
#implementation AvsAViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self refreshData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[frc sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id<NSFetchedResultsSectionInfo> sectionInfo = [[frc sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
// Customize the appearance of table view cells.
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// Configure the cell to show the activity's name
ListActivity *thisActivity = [frc objectAtIndexPath:indexPath];
cell.textLabel.text = thisActivity.activityName;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"aVSaCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[self configureCell:cell atIndexPath:indexPath];
cell.textLabel.textColor = [UIColor redColor];
NSAttributedString *attString;
attString = cell.textLabel.attributedText;
return cell;
}
// Section Label
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *sectionLabel = [[[frc sections] objectAtIndex:section]name];
return [sectionLabel uppercaseString];
}
-(void) refreshData
{
//This was the turning point for proper MR grouping. The two Properties (activityCategory and activityName) are used as Sort descriptors in the underlying core data methods
frc = [ListActivity MR_fetchAllSortedBy:#"activityCategory,activityName"
ascending:YES withPredicate:nil
groupBy:#"activityCategory"
delegate:nil];
[self.myTableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Make sure "Clip Subviews" is selected for that UITableView in the Property Inspector, and that the table's clipsToBounds is not set to NO somewhere in the code.
I resolved the issue by simply deleting the TableView and dragging in a new one, wiring it up. The problem is therefore fixed, but I have no idea what caused it.
Thanks to #drhr, who commented, and all others who took a look!
Edit:
Just wondering if anyone else has run across this problem. I just had it repeat on another tableview, and had to resolve it as above. FWIW, I'm using Xcode 5, and developing an iPhone app.
I guess fixed is good, but it would be nice to actually know what caused the problem.
I've created a subclass of UITableViewCell for an iPad app. I need to dynamically generate text fields, take input from the user, and then store that information in an array. I thought of asking the UITableViewCell for the UITextField.text object, which would hold whatever the user wrote before my View Controller's segue (I'm saving the NSString objects upon the segue being called). So I've got an array of UITableViewCells which I ask for the UITextField.text object. But for some reason while my UITableViewCell subclass is being created, my UITextField is not. I can call UITableViewSubclass and it's initialized, but UITableViewSubclass.UITextField is nil.
Here's my UITableViewCell Subclass header (Yes, the UITextField is connected in the storyboard):
#import <UIKit/UIKit.h>
#interface ConditionCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UITextField *condition;
#end
Here's my implementation file:
#import "ConditionCell.h"
#implementation ConditionCell
#synthesize condition;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.condition = (UITextField *)[self viewWithTag:10];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
This here is the Table View Controller handling the table that contains the cells:
.h file:
#import <UIKit/UIKit.h>
#import "ConditionCell.h"
#interface ConditionsTableViewController : UITableViewController
#property (strong, nonatomic) NSMutableArray *conditionCellArray;
- (void)addNewConditionCell;
#end
.m file:
#import "ConditionsTableViewController.h"
#interface ConditionsTableViewController ()
#end
#implementation ConditionsTableViewController
#synthesize conditionCellArray = _conditionCellArray;
- (NSMutableArray *)conditionCellArray
{
if (_conditionCellArray == nil) {
// Create the array object
_conditionCellArray = [[NSMutableArray alloc] init];
}
return _conditionCellArray;
}
- (void)addNewConditionCell
{
ConditionCell *condCell = [[ConditionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"conditionCell"];
[self.conditionCellArray addObject:condCell];
[self.tableView beginUpdates];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.conditionCellArray.count-1 inSection:0];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
[self.tableView reloadData];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// 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)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (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.conditionCellArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"conditionCell";
ConditionCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[ConditionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
//cell.condition = (UITextField *)[cell viewWithTag:1];
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;
}
*/
#pragma mark - Table view 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
This Table View Controller lives inside a UIView Controller as the table view does not take up the whole screen. When the user presses an 'ok' button there is a segue that is triggered and it is here that I ask this Table View Controller for the array containing the UITableViewCells, which I then run through a foreach to get their .text properties. Unfortunately I can't seem to get anything I input into the text fields, hence the .text's are always nil. If anyone could help me with this issue it would be greatly appreciated!
You might find this much easier to do using the free Sensible TableView framework. The framework has these text field cells out of the box, and can even create them automatically from your array.
I figured out a better way to do what I wanted to do here that works. Turns out that the way iOS's UITableView works is totally different from what I wanted to do. UITableView works by looking at your storyboard and given the identifiers for the cells, it creates them and allows you to set their properties within the cellForRowAtIndexPath method. However, when the cell goes offscreen, it is not retained as it's own separate object; it is reused. So, you can think of it as if when you scroll a table view, the cells that disappear to one end reappear on the other end with new information. This is key - UITableView want YOU to provide the cell's information. It was not made for input of information directly on a UITableViewCell, which is what I wanted to do.
So what I ended up doing was copy-pasting my cells into their own .xib file, and in the subclass initWithStyle:reuseIdentifier method, do:
NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:#"ConditionCell" owner:self options:nil];
self = [nibArray objectAtIndex:0];
And that creates the cell with whatever style - setup - UI elements you want.
Next, I want to hold on to a reference to the cell, because that cell has a textbox, and I need to save what's on the textbox when the user presses a "done" button. However, testing revealed the reuse problem I explained above. So how to do this? In my Table's view controller, whenever the user wants to add a new textbox (and presses the button to do so) I have a method which does
[self.conditionCellArray insertObject:[[ConditionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"conditionCell"] atIndex:0];
This adds a new cell to an array - this is important because I need to have a reference to ALL cells at all times. (It is adding the cell at index 0 because I want to insert it at the top). Then, in the cellForRowAtIndexPath method, I did
return [self.conditionCellArray objectAtIndex:indexPath.row];
Which will return the corresponding cell. Bear in mind, from what I have read this whole thing about keeping a reference to each and every cell in the table is contrary to Apple's stated best practices when using UITableView. However, as I said before, UITableView is meant to display information, not to gather it from user input. So this is why I had to break the rules, if you will, to achieve the desired effect (that I wanted). I hope this helps others who are looking to do the same thing; and if there is a better way don't be shy about telling me.
EDIT: Oh by the way, when you copy paste the cells created in storyboard to their own .xib file make sure to disconnect any IBOutlets and change their class back to UITableViewCell. That way there won't be any problems or conflicts when you connect your .xib file cell.
Why is my table view blank? It was fine until I added "initWithStyle"
Here is what it looks like:
And here is what my code looks like:
Here is my .h:
#import <UIKit/UIKit.h>
#interface TableViewController : UITableViewController {
NSMutableArray *jokes;
IBOutlet UITableView *jokeTableView;
}
#property (nonatomic, retain) NSMutableArray *jokes;
#property (retain) UITableView *jokeTableView;
#end
And here is my implementation file:
#import "TableViewController.h"
#import "Joke.h"
#implementation TableViewController
#synthesize jokes;
#synthesize jokeTableView;
- (void)awakeFromNib {
[jokeTableView init];
}
- (id)initWithStyle:(UITableViewStyle)style {
if (self = [super initWithStyle:style]) {
self.jokes = [NSMutableArray arrayWithObjects:
[Joke jokeWithValue:#"If you have five dollars and Chuck Norris has five dollars, Chuck Norris has more money than you"],
[Joke jokeWithValue:#"There is no 'ctrl' button on Chuck Norris's computer. Chuck Norris is always in control."],
[Joke jokeWithValue:#"Apple pays Chuck Norris 99 cents every time he listens to a song."],
[Joke jokeWithValue:#"Chuck Norris can sneeze with his eyes open."],
nil];
self.jokeTableView.rowHeight = 30.0;
// self.jokeTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
self.jokeTableView.sectionHeaderHeight = 0;
}
return self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Saying how many sections wanted (Just like in address, where sorts by first name)
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [jokes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Team";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier] autorelease];
}
Joke *j = (Joke *)[jokes objectAtIndex:indexPath.row];
if( j )
cell.text = j.joke;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[jokes release];
[jokeTableView release];
[super dealloc];
}
#end
If your view controller is being loaded from a nib, you'll need to override the initWithCoder: method, not initWithStyle:.
However, the normal solution would be to add all your custom initialization code in the awakeFromNib: method, this is called after the nib is loaded and all outlets are connected, so it makes a great place to do any initialization you need.
See the Apple docs on awakeFromNib: for details on object instantiation from nibs. Also, if you have access to the 3.0 beta docs, do a search for awakeFromNib:, the updated wording gives a better explanation of which methods are called and when.
P.S. You shouldn't be calling [jokeTableView init] in your code, this will be done automatically when the nib is unpacked.
Edit: Since you are setting properties for your table view from your initialization code, this should definitely be in awakeFromNib:, not initWithCoder: or initWithStyle:.
Looking at the screenshot, you might also want to make sure with Interface Builder that the UITableView is placed correctly in the nib file for your view controller, and that the code (or nib) that creates your view controller is referring to the right nib file - if it were just the data for the table view that had not loaded, you would see gray lines between empty cells, not just blank white space like in that image.
initWithStyle is not the same as initWithCoder. Your constructor probably isn't even getting called.
I don't know if it's the cause of your problem, but that random [jokeTableView init] in awakeFromNib is certainly wrong and could cause problems like this. init should never be called without an attached alloc*, and in this case I doubt either is needed since the table view has presumably already been created elsewhere.
(* The one exception to this rule, obviously, is when you're overriding an init method and calling super.)
Well, if you are initializing this controller using initWithStyle and you previously were calling initWithCoder , that is your problem.
You are loading your self.jokes in initWithCoder. You should move that code to viewDidLoad or to your new initWithStyle method
// move this
self.jokes = [NSMutableArray arrayWithObjects:
[Joke jokeWithValue:#"If you have five dollars and Chuck Norris has five dollars, Chuck Norris has more money than you"],
[Joke jokeWithValue:#"There is no 'ctrl' button on Chuck Norris's computer. Chuck Norris is always in control."],
[Joke jokeWithValue:#"Apple pays Chuck Norris 99 cents every time he listens to a song."],
[Joke jokeWithValue:#"Chuck Norris can sneeze with his eyes open."],
nil];
Get rid of this:
- (void)awakeFromNib {
[jokeTableView init];
}
you're already doing initialization in initWithStyle:
I think the main problem is that you need to replace:
- (id)initWithStyle:(UITableViewStyle)style {
if (self = [super initWithStyle:style]) {
(and the closing bracket)
with
- (void)viewDidLoad {
Also, you shouldn't have to end a NSMutableArray with nil.