Adding values in a table view cell - iphone

I have two view controllers. The CardWallet View Controller is my table view. Then the AddCard View Controller is where I input values for a new instance of an object named Card. So far, I am adding those Card instances in an array named myWallet which is in my CardWallet View Controller using a delegate and it works.
What I want is, after clicking the button in my AddCard View Controller, a new table cell will appear in my Card Wallet View, with the name depending on the recently added instance of Card. Below is my code, kindly check why is it that when I'm finished adding a new instance of Card, nothing appears in my table. I've done some research and went through some tutorials, this one is good, http://kurrytran.blogspot.com/2011/10/ios-5-storyboard-and.html, it helped me a lot regarding table view controllers. However, the tutorial doesn't cater my main concern for it's table's values only come from an array with static values.
Thanks!
CardWalletViewController.h
#import <UIKit/UIKit.h>
#interface CardWalletViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
}
#property (nonatomic, strong) NSMutableArray *myWallet;
-(void) printArrayContents;
#end
CardWalletViewController.m
#import "CardWalletViewController.h"
#import "AddCardViewController.h"
#import "Card.h"
#interface CardWalletViewController () <AddCardDelegate>
#end
#implementation CardWalletViewController
#synthesize myWallet = _myWallet;
- (NSMutableArray *) myWallet
{
if (_myWallet == nil) _myWallet = [[NSMutableArray alloc] init];
return _myWallet;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showAddCardVC"]) {
AddCardViewController *addCardVC = (AddCardViewController *)segue.destinationViewController;
addCardVC.delegate = self;
}
}
- (void)printArrayContents
{
// I want to show the name of each instance of card
for ( int i = 0; i < self.myWallet.count; i++) {
Card *cardDummy = [self.myWallet objectAtIndex:i];
NSLog(#"Element %i is %#", i,cardDummy.name );
}
}
- (void)addCardViewController:(AddCardViewController *)sender didCreateCard:(Card *)newCard
{
// insert a new card to the array
[self.myWallet addObject:newCard];
[self printArrayContents];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
// Release any retained subviews of the main view.
}
- (void)viewWillAppear:(BOOL)animated
{
}
- (void)viewWillDisappear:(BOOL)animated
{
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//this method will return the number of rows to be shown
return self.myWallet.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
//---------- CELL BACKGROUND IMAGE -----------------------------
UIImageView *imageView = [[UIImageView alloc] initWithFrame:cell.frame];
UIImage *image = [UIImage imageNamed:#"LightGrey.png"];
imageView.image = image;
cell.backgroundView = imageView;
[[cell textLabel] setBackgroundColor:[UIColor clearColor]];
[[cell detailTextLabel] setBackgroundColor:[UIColor clearColor]];
//this will show the name of the card instances stored in the array
//
for ( int i = 0; i < self.myWallet.count; i++) {
Card *cardDummy = [self.myWallet objectAtIndex:i];
cell.textLabel.text = cardDummy.name;
}
//Arrow
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
AddCardViewController.h
#import <UIKit/UIKit.h>
#import "Card.h"
#class AddCardViewController;
#protocol AddCardDelegate <NSObject>
- (void)addCardViewController:(AddCardViewController *)sender
didCreateCard:(Card *) newCard;
#end
#interface AddCardViewController : UIViewController <UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UITextField *cardNameTextField;
#property (strong, nonatomic) IBOutlet UITextField *pinTextField;
#property (strong, nonatomic) IBOutlet UITextField *pointsTextField;
#property (nonatomic, strong) id <AddCardDelegate> delegate;
#end
AddCardViewController.m
#import "AddCardViewController.h"
#import "Card.h"
#import "CardWalletViewController.h"
#interface AddCardViewController ()
#end
#implementation AddCardViewController
#synthesize cardNameTextField = _cardNameTextField;
#synthesize pinTextField = _pinTextField;
#synthesize pointsTextField = _pointsTextField;
#synthesize delegate = _delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.cardNameTextField becomeFirstResponder];
}
- (void) viewWillDisappear:(BOOL)animated
{
}
- (BOOL) textFieldShouldReturn:(UITextField *)textField{
if ([textField.text length]) {
[self.cardNameTextField resignFirstResponder];
[self.pinTextField resignFirstResponder];
[self.pointsTextField resignFirstResponder];
return YES;
}
else {
return NO;
}
}
- (void)viewDidLoad
{
self.cardNameTextField.delegate = self;
self.pinTextField.delegate = self;
self.pointsTextField.delegate = self;
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setCardNameTextField:nil];
[self setPinTextField:nil];
[self setPointsTextField:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)addCard:(id)sender
{
Card *myNewCard = [[Card alloc] init];
myNewCard.name = self.cardNameTextField.text;
myNewCard.pin = self.pinTextField.text;
myNewCard.points = [self.pointsTextField.text intValue];
// to check if the text fields were filled up by the user
if ([self.cardNameTextField.text length] && [self.pinTextField.text length] && [self.pointsTextField.text length])
{
[[self presentingViewController] dismissModalViewControllerAnimated:YES];
NSLog(#"name saved %#", myNewCard.name);
NSLog(#"pin saved %#", myNewCard.pin);
NSLog(#"points saved %i", myNewCard.points);
[self.delegate addCardViewController:self didCreateCard:myNewCard];
// to check if there is a delegate
if (self.delegate){
NSLog(#"delegate is not nil");
}
}
}
#end
Card.h
#import <Foundation/Foundation.h>
#interface Card : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *pin;
#property (nonatomic) int points;
#end
Card.m
#import "Card.h"
#implementation Card
#synthesize name = _name;
#synthesize pin = _pin;
#synthesize points = _points;
#end

I should get the obvious question out of the way before anyone starts dwelling too deep into this - do you have some mechanism of reloading the data after you add a new card (e.g. call [tableView reloadData] from the CardWalletViewController)? I didn't see anything like that, and I've always used this whenever I add something new to a table.*
*If the table contains too much data, you may want to reload only a part of it.
Update 1: Class Inheritance
Every Objective C class has to inherit from some other class in the hierarchy. By default, unless you say otherwise, all of your custom classes will inherit from NSObject, which is the most generic object out there (equivalent of Object, if you've done Java programming). Changing the parent class is done by simply changing the class after the : in your interface declaration. So when you say
#interface CardWalletViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
what you are saying is "declare a CardWallerViewController custom class that inherits from UIViewController and implements the UITableViewDelegate and UITableViewDataSource protocols" (if you don't know what protocols are, ask).
Now, back to your question. Changing the parent class should be easy now - you just change that : UIViewController to : UITableViewController and you are done. After you do this, your CardWallerViewController (also, "Waller", really?) will behave like a UITableView, not like a generic UIView. When doing this, you will also not need to tell it to implement the delegate and dataSource protocols - UITableViewController does that by default.
As a final note, when you add new files to your Xcode project, you can tell the program which class you want to inherit from. It defaults to UIView for views, but that's simply because this is the most generic view class. As you begin to use more specific classes (UITableViewController, UIPickerViewController, UITableViewCell, to name a few), changing the parent class off the bat will prove to be more than helpful.
Update 2: UITableViewCells
That for-loop you've got going there is a (relatively) lot of work you don't need to do. Since your table corresponds directly to your myWallet property, this means that the cell in row N of your table will represent the card at index N of your array. You can use that to your advantage. In the tableView:cellForRowAtIndexPath: method, you tell the program what to do with the cell at the specific indexPath (which is really just section + row for that table). The trick is, this method instantiates the cells one at a time. So instead of doing the for-loop, you can just say (at the end)
cell.textLabel.text = [self.myWallet objectAtIndex:indextPath.row].name;
For any cell in row N, this will look at the Nth Card object inside myWallet and use its name to set the cell's textLabel.text. If it gives you problems, save [self.myWallet objectAtIndex:indextPath.row] in some tempCard object, and then do cell.textLabel.text = tempCard.name. This is also the proper way to populate cells in a tableView - you only care about one cell at a time, because that's how the method works anyway. Imagine if you had 1,000,000 Cards inside your array - doing the for-loop would force the program to go through the array 1,000,000 times for each cell. Say hello to a 1,000,000,000,000 operations :)

i think u can add the imageview as subview to cell
UIImageView *imageView = [[UIImageView alloc] initWithFrame:cell.frame];
UIImage *image = [UIImage imageNamed:#"LightGrey.png"];
imageView.image = image;
[cell addSubview:imageView];
[[cell textLabel] setBackgroundColor:[UIColor clearColor]];
[[cell detailTextLabel] setBackgroundColor:[UIColor clearColor]];

Related

Passing Data from Dynamic tableView to Static TableView

Hi Let me try to clarify my issue. I have two TableViews, one is static and the other is dynamic. The static= RootVC and Dynamic=FirstVC. In FirstVC i have data that I want to select,save and pass the saved data to a UILabel in RootVC. 1)When I run my App data is selected however it is not saved or passed to my rooVC. I was using delegates and was advice not to use "delegate" but use "Blocks". But still i'm facing the same issue. Here is my code:
in rootVC.h
#import <UIKit/UIKit.h>
#interface RootViewController : UITableViewController
{
NSString *getRepeatLabel;
}
#property (strong, nonatomic) IBOutlet UILabel *repeatLabel;
#property (strong, nonatomic) IBOutlet UILabel *repeatDetail;
#property (nonatomic,strong) NSString *getRepeatLabel;
#end
in my rootVC.m
#import "RootViewController.h"
#interface RootViewController ()
#end
#implementation RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_repeatLabel.text = #"Repeat";
_repeatDetail.text = getRepeatLabel;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destinationController = segue.destinationViewController;
if( [destinationController isKindOfClass:[FirstViewController class]] )
{
[(FirstViewController *)destinationController setCompletionBlock:^(NSString *getRepeatLabel;)
{
// do something here with your string // maybe you must reload your table // it depends on where your returning data needs to display <--------Not sure what to do here
// NSDateFormatter*dateFormatter = [[NSDateFormatter alloc]init];
// NSArray*days = [dateFormatter shortWeekdaySymbols]; <------Here I would like when data is selected to show days in short symbol
NSLog (#"The selected day/s is %#", getRepeatLabel); <---nothing displaying on console
}];
}
}
#end
in FirstVC.h
#import <UIKit/UIKit.h>
#import "RootViewController.h"
typedef void(^WeekdayCompletionBlock)(NSString *dayName);
#interface FirstViewController : UITableViewController
{
NSString *dayName;
}
#property (nonatomic, strong) WeekdayCompletionBlock completionBlock;
#property (nonatomic,strong) NSString *dayName;
- (IBAction)save:(id)sender;
#end
in FirstVC.m
#import "FirstViewController.h"
#import "RootViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize completionBlock;
#synthesize dayName;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Initialize table data
completionBlock = [NSArray arrayWithObjects:#"Sunday", #"Monday", #"Tuesday", #"Wednesday", #"Thursday", #"Friday", #"Saturday", nil];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [completionBlock count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"RepeatCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [completionBlock objectAtIndex:indexPath.row];
return cell;
}
// Called after the user changes the selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog (#"The selected day/s is %#", [completionBlock objectAtIndex:indexPath.row]);
_getRepeatLabel = completionBlock; //<-----------string from RootVC gives error "undeclared _getRepeatLabel"
}
- (IBAction)save:(id)sender
{
NSUserDefaults *myNewWeekString = [NSUserDefaults standardUserDefaults];
[myNewWeekString setObject:completionBlock forKey:#"%#"];
[myNewWeekString synchronize];
self.completionBlock(myNewDayOfWeekString) <------error myNewDayOfWeekString undeclared and if i declare it here it complains about incompatibility
}
#end
Your code is a little bit wrong. I think you don't really understand block.
You want to pass more than string so the best way to do that is via array. Change block definition to accept array instead of string:
typedef void(^WeekdayCompletionBlock)(NSArray *dayName);
Change declaration of your property in FirstVC.h to:
#property (nonatomic, copy) NSArray *completionBlock; //This is your array, you use it as data source, It's not a block
//Add your block property
// This is your block property you will use it to pass the data between view controllers
#property (copy) WeekdayCompletionBlock returnBlock;
//Add property to keep your selected days
#property (nonatomic, strong) NSMutableArray *returnArray;
Add this line to viewDidLoad method:
self.returnArray = [[NSMutableArray alloc] init];
Change your didSelectRowAtIndexPath method in FirstVC.m to:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
//remove data from array
[self.returnArray removeObject:[completionBlock objectAtIndex:indexPath.row]];
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
//add data to array
[self.returnArray addObject:[completionBlock objectAtIndex:indexPath.row]];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
In your save: method call block and pass value to rootVC replace line:
self.completionBlock(myNewDayOfWeekString);
with:
if (self.returnBlock)
{
self.returnBlock(self.returnArray);
}
[self.navigationController popViewControllerAnimated:YES];
The last change left to do is set up ablok in your rootVC.m file. Replace line:
[(FirstViewController *)destinationController setCompletionBlock:
with (nsstring needs to be replaced with nsarray - you pass array with all of the selected data)
[(FirstViewController *)destinationController setCompletionBlock:^(NSArray *getRepeatLabel)
You set up block not NSArray.
I don't know what are you trying to do here:
[myNewWeekString setObject:completionBlock forKey:#"%#"];
You are using %# as a key. It should be text for example #"MY_KEY_FOR_ACCESING_DAYSOFWEEK". You are saving completionBlock it's all of your days if you want to save just selected days replace it with self.returnArray.
Hope this help.

Adding data to NSMutableArray from another view [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I want to read the NSMutableArray *menu from my MenuViewController.h, i am tired of trying. This is my code now:
// ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
// ViewController.m
#import "ViewController.h"
#import "MenuViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#pragma mark - view Did Load, View Will Appear & didReceiveMemoryWarning
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)viewWillAppear:(BOOL)animated {
MenuViewController *menuView = [[MenuViewController alloc] init];
[self.view addSubview:menuView.view]; // this line is new
NSLog(#"%#", menuView.self.menu);
[menuView.menu addObject:#"Darommmm"];
NSLog(#"%#", menuView.menu);
[menuView.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
So this is the code of my viewController.m and .h. Below i will show the code of MenuViewController.h and .m
// MenuViewController.h
#import <UIKit/UIKit.h>
#interface MenuViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#property (nonatomic, retain) NSMutableArray *menu;
#property (nonatomic, retain) NSMutableArray *sections;
#end
// MenuViewController.m
#import "MenuViewController.h"
#interface MenuViewController ()
#end
#implementation MenuViewController
#synthesize menu, sections, tableView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
#pragma mark - View Did load, View Will Appear & didReceiveMemoryWarning
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// set background to transparent + no seperator
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
self.tableView.backgroundColor = [UIColor clearColor];
// allocate the mutable array for our menu
self.menu = [[NSMutableArray alloc] init];
// standard menu items to our object
[self.menu addObject:#"Dashboard"];
[self.menu addObject:#"Chats"];
[self.menu addObject:#"Visitors"];
[self.menu addObject:#"Log Out"];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.menu count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [self.menu objectAtIndex:indexPath.row];
cell.textLabel.textColor = [UIColor whiteColor];
UIImageView *bg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"sidebarcell"]];
[bg setFrame:CGRectMake(0, 0, 161.5, 42.5)];
// Configure the cell...
cell.backgroundView = bg;
return cell;
}
I can't see what i'm doing wrong, when i try to NSLog the menuView.self.menu i get (null).. Hope you guys can help me out! Cheers.
MenuViewController's menu variable never appears to be initialized by the time you're using it, so it's just nil. Put an array in there in your init method (and don't set it in your viewDidLoad if you've already initialized it).
menu is nil at the time you're adding elements to it. You initialize it in viewDidLoad of MenuViewController, which is called only after you add that controller to a window. You can fix your issue by using this code, however I wouldn't recommend this as a permanent fix.
MenuViewController *menuView = [[MenuViewController alloc] init];
[self.view addSubview:menuView.view] // this line is new
NSLog(#"%#", menuView.self.menu);
[menuView.menu addObject:#"Darommmm"];
NSLog(#"%#", menuView.menu);
[menuView.tableView reloadData];
You also don't need to call self before accessing the properties of a class.
The proper approach here would be to move the initialization of the NSMutableArray to the controller's init method.

Passing data from plist to detail view

I have a plist (array of dictionaries) which populates a table view and works properly. I use Xcode 4 with storyboards.
Now I've created a detail view from a regular UIViewController and of course I want the selected name to be displayed in the nameLabel in the detail view. But I can't make the right connection. This is my code so far:
WineObject.m:
#import "WineObject.h"
#implementation WineObject
#synthesize libraryContent, libraryPlist;
- (id)initWithLibraryName:(NSString *)libraryName {
if (self = [super init]) {
libraryPlist = libraryName;
libraryContent = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:libraryPlist ofType:#"plist"]];
}
return self;
}
- (NSDictionary *)libraryItemAtIndex:(int)index {
return (libraryContent != nil && [libraryContent count] > 0 && index < [libraryContent count])
? [libraryContent objectAtIndex:index]
: nil;
}
- (int)libraryCount {
return (libraryContent != nil) ? [libraryContent count] : 0;
}
- (void) dealloc {
if (libraryContent) [libraryContent release];
[super dealloc];
}
#end
ViewController.h:
#import <UIKit/UIKit.h>
#class WineObject;
#interface WinesViewController : UITableViewController {
WineObject *wine;
}
#end
ViewController.m:
#import "WinesViewController.h"
#import "WineObject.h"
#import "WineCell.h"
#interface WinesViewController ()
#end
#implementation WinesViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (void)viewWillAppear:(BOOL)animated {
wine = [[WineObject alloc] initWithLibraryName:#"Wine"];
self.title = #"Vinene";
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
- (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 [wine libraryCount];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"wineCell";
WineCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
cell.nameLabel.text = [[wine libraryItemAtIndex:indexPath.row] valueForKey:#"Name"];
cell.districtLabel.text = [[wine libraryItemAtIndex:indexPath.row] valueForKey:#"District"];
cell.countryLabel.text = [[wine libraryItemAtIndex:indexPath.row] valueForKey:#"Country"];
cell.bottleImageView.image = [UIImage imageNamed:[[wine libraryItemAtIndex:indexPath.row] valueForKey:#"Image"]];
cell.flagImageView.image = [UIImage imageNamed:[[wine libraryItemAtIndex:indexPath.row] valueForKey:#"Flag"]];
cell.fyldeImageView.image = [UIImage imageNamed:[[wine libraryItemAtIndex:indexPath.row] valueForKey:#"Fylde"]];
cell.friskhetImageView.image = [UIImage imageNamed:[[wine libraryItemAtIndex:indexPath.row] valueForKey:#"Friskhet"]];
cell.garvesyreImageView.image = [UIImage imageNamed:[[wine libraryItemAtIndex:indexPath.row] valueForKey:#"Garvesyre"]];
return cell;
}
#pragma mark - Table view delegate
#end
WineCell.h:
#import <UIKit/UIKit.h>
#interface WineCell : UITableViewCell
#property (nonatomic, strong) IBOutlet UILabel *nameLabel;
#property (nonatomic, strong) IBOutlet UILabel *districtLabel;
#property (nonatomic, strong) IBOutlet UILabel *countryLabel;
#property (nonatomic, strong) IBOutlet UIImageView *bottleImageView;
#property (nonatomic, strong) IBOutlet UIImageView *flagImageView;
#property (nonatomic, strong) IBOutlet UIImageView *fyldeImageView;
#property (nonatomic, strong) IBOutlet UIImageView *friskhetImageView;
#property (nonatomic, strong) IBOutlet UIImageView *garvesyreImageView;
#end
Are you using a XIB for interface or generating it programmatically?
If you are using a XIB, the issue is that you aren't loading it up:
Change
winesDetailViewController = [[WinesDetailViewController alloc] init];
To
winesDetailViewController = [[WinesDetailViewController alloc] initWithNibName:#"YourNibNameHere" bundle:nil];
Or, if you are generating it programmatically, you must first set nameLabel or it will be nil. #synthesize doesn't set the variable, it simply generates getters and setters so that you can set it from outside.
Inside your viewDidAppear: (or better yet inside your init) add:
self.nameLabel=[[UILabel alloc] initWithFrame:CGRectMake(100,100,100,100)];
EDIT: If you are using Storyboards, it appears that you have to do the following.
Storyboards are all about relationships. Inside the story board editor, you add buttons and tell them which view controller they connect to. The same idea applies to TableView Cells. You can add a prototype table view cell (and customize it) and assign a relationship to it. The relationship you will want to give it is your detail view.
1.) Subclass UITableViewCell and give it a property that is the dictionary that you are trying to send to the detail view
2.) When creating cells (cellForRowAtIndexPath:) you will need to make sure to dequeue your custom cell and assign your dictionary to the property that you gave it.
3.) Make sure that your detail view has the identifier: DetailView
4.) Inside the table view controller, add the following code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"DetailView"])
{
//This works because by the time prepareForSeque: is called, the navigationController has loaded the new view
((DetailView *)[[self.navigationController viewControllers] objectAtIndex:0]).dataProperty=((MyCustomTableViewCell *)sender).dataProperty;
}
}
That ought to do it!

How to sum contents of reusable Custom Cells for a Table View that acts as a Calculator

I built a table view, with Custom Table View Cells, where each cell has several UITextFields that allow the user to enter numbers that provide a calculation. The cell hast a subtotal UITextField that provides the result for that cell.
My problem is that I want to take the subtotal of that cell, and of each additional cell that the User uses, and provide a Total on a different UIView.
I do not know how to take the value of each subtotal for each cell, and furthermore, how can I know how many cells the user used, and all of this in order to provide the user with a TOTAL in a different view.
What would be the best way to achieve this?
Here is the Code.
I want to add new cells and be able to add them to the calculation. But each cell will hold different values that the user will provide.
Best!
#import <UIKit/UIKit.h>
#interface ProCalculator : UIViewController <UITableViewDelegate, UITableViewDataSource> {
UITextField *totalField;
UITextField *differenceField;
UITextField *productField;
UITextField *price1Field;
UITextField *discount1P1Field;
UITextField *discount2P1Field;
UITextField *subtotal1Field;
UITextField *product2Field;
UITextField *price2Field;
UITextField *discount1P2Field;
UITextField *discount2P2Field;
UITextField *subtotal2Field;
}
#property (nonatomic, retain) IBOutlet UITextField *totalField;
#property (nonatomic, retain) IBOutlet UITextField *differenceField;
#property (nonatomic, retain) IBOutlet UITextField *productField;
#property (nonatomic, retain) IBOutlet UITextField *price1Field;
#property (nonatomic, retain) IBOutlet UITextField *discount1P1Field;
#property (nonatomic, retain) IBOutlet UITextField *discount2P1Field;
#property (nonatomic, retain) IBOutlet UITextField *subtotal1Field;
#property (nonatomic, retain) IBOutlet UITextField *product2Field;
#property (nonatomic, retain) IBOutlet UITextField *price2Field;
#property (nonatomic, retain) IBOutlet UITextField *discount1P2Field;
#property (nonatomic, retain) IBOutlet UITextField *discount2P2Field;
#property (nonatomic, retain) IBOutlet UITextField *subtotal2Field;
-(IBAction)calculateDiscounts:(id)sender;
-(IBAction)removeKeyboard;
#end
#import "ProCalculator.h"
#import "ProductCell.h"
#implementation ProCalculator
#synthesize totalField, differenceField, productField, price1Field, discount1P1Field, discount2P1Field, subtotal1Field;
#synthesize product2Field, price2Field, discount1P2Field, discount2P2Field, subtotal2Field;
-(IBAction)calculateDiscounts:(id)sender
{
//Calculate product 1 within first Cell
NSString *firstPrice = self.price1Field.text;
NSString *discount1P1 = self.discount1P1Field.text;
NSString *discount2P1 = self.discount2P1Field.text;
double subtotal1WithDiscount1;
double subtotal1WithDiscount2;
double firstPriceDouble = [firstPrice doubleValue];
double discount1P1Double = [discount1P1 doubleValue];
double discount2P1Double = [discount2P1 doubleValue];
double percentageDiscount1P1;
double percentageDiscount2P1;
double savings1P1;
double savings2P1;
percentageDiscount1P1 = discount1P1Double / 100;
percentageDiscount2P1 = discount2P1Double / 100;
savings1P1 = firstPriceDouble * percentageDiscount1P1;
subtotal1WithDiscount1 = firstPriceDouble - savings1P1;
savings2P1 = subtotal1WithDiscount1 * percentageDiscount2P1;
subtotal1WithDiscount2 = subtotal1WithDiscount1 - savings2P1;
NSString *finalSubtotal1 = [[NSString alloc] initWithFormat:#"$ %.02f", subtotal1WithDiscount2];
self.subtotal1Field.text = finalSubtotal1;
//Calculate product 2 within second Cell (Instead of Building more cells, I need to get information from User Input to create Cells and store information from them and add them to the calculation.
NSString *secondPrice = self.price1Field.text;
NSString *discount1P2 = self.discount1P2Field.text;
NSString *discount2P2 = self.discount2P2Field.text;
double subtotal2WithDiscount1;
double subtotal2WithDiscount2;
double secondPriceDouble = [secondPrice doubleValue];
double discount1P2Double = [discount1P2 doubleValue];
double discount2P2Double = [discount2P2 doubleValue];
double percentageDiscount1P2;
double percentageDiscount2P2;
double savings1P2;
double savings2P2;
percentageDiscount1P2 = discount1P2Double / 100;
percentageDiscount2P2 = discount2P2Double / 100;
savings1P2 = secondPriceDouble * percentageDiscount1P2;
subtotal2WithDiscount1 = secondPriceDouble - savings1P2;
savings2P2 = subtotal2WithDiscount1 * percentageDiscount2P2;
subtotal2WithDiscount2 = subtotal2WithDiscount1 - savings2P2;
NSString *finalSubtotal2 = [[NSString alloc] initWithFormat:#"$ %.02f", subtotal2WithDiscount2];
self.subtotal1Field.text = finalSubtotal2;
//Calculate Total
double totalAmount;
totalAmount = subtotal1WithDiscount2 + subtotal2WithDiscount2;
NSString *theTotal = [[NSString alloc] initWithFormat:#"$ %.02f", totalAmount];
self.totalField.text = theTotal;
//Calculate Money Saved
double moneySaved;
moneySaved = savings1P1 + savings2P1 + savings1P2 + savings2P2;
NSString *theMoneySaved = [[NSString alloc] initWithFormat:#"$ %.02f", moneySaved];
self.differenceField.text = theMoneySaved;
}
-(IBAction)removeKeyboard
{
[self.productField resignFirstResponder];
[self.price1Field resignFirstResponder];
[self.discount1P1Field resignFirstResponder];
[self.discount2P1Field resignFirstResponder];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#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 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ProductTableViewCell";
ProductCell *cell = (ProductCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLabel = [[NSBundle mainBundle] loadNibNamed:#"ProductTableViewCell" owner:self options:nil];
for (id currentObject in topLabel) {
if ([currentObject isKindOfClass:[ProductCell class]]) {
cell = (ProductCell *) currentObject;
break;
}
}
}
return cell;
}
#end
First of all, I assume you are using a custom UITableViewCell, which has a textfield as one of it's parameters.
I would suggest making an associated model with these cells, which has a parameter which stores the value of the textfield every time the user enters in new information. Something like:
#interface TableViewCellModel : NSObject {
NSString * _valueOfTextfield;
}
#property (nonatomic, retain) NSString * valueOfTextfield;
#end
#implementation TableViewCellModel
#synthesize valueOfTextfield = _valueOfTextfield;
#end
Then, when the textfield is pressed, and the user enters in the information and resigns the textfield, update the associated model of the cell to store the value of the textfield.
When you want to show the TOTAL of the textfields in all the cells, just look at each of the cells corresponding models, and check if the valueOfTextfield property is nil or not.
One warning though, if each of the custom UITableViewCells has their own textfield, you could have some issues with performance, as well as your touch events in the cells. You may want to look into having a singleton class which handles the textfields separately, and each one of the custom cells having a reference to this singleton class.
EDIT: I have played with some code, and I think I have what you want now. You'll need a few files, and this gets a bit long. They will be in .h, then .m pairs.
#interface TableViewModel : NSObject {
int _index;
NSString * _textFieldValue;
}
#property (nonatomic, assign) int index;
#property (nonatomic, retain) NSString * textFieldValue;
#end
#import "TableViewModel.h"
#implementation TableViewModel
#synthesize index = _index;
#synthesize textFieldValue = _textFieldValue;
#end
Then,
#import <UIKit/UIKit.h>
#class TableViewModel;
#interface TableViewCell : UITableViewCell {
IBOutlet UILabel * _label;
}
#property (nonatomic, retain) TableViewModel * tableViewModel;
- (IBAction)useTextField;
#end
#import "TableViewCell.h"
#import "TableViewModel.h"
#import "AppDelegate.h"
#implementation TableViewCell
- (void)dealloc; {
[super dealloc];
}
- (void)setTableViewModel:(TableViewModel *)tableViewModel; {
_label.text = [tableViewModel textFieldValue];
}
- (TableViewModel *)tableViewModel; {
return nil;
}
- (IBAction)useTextField; {
[[AppDelegate appDelegate] useTextFieldForIndex:[self.tableViewModel index]];
}
#end
and finally,
#import <UIKit/UIKit.h>
#class TableViewCell;
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate> {
int _index;
NSMutableArray * _items;
IBOutlet TableViewCell * _cell;
IBOutlet UITableView * _tableView;
IBOutlet UITextField * _textField;
}
- (void)useTextFieldForIndex:(int)aIndex;
#end
#import "ViewController.h"
#import "TableViewModel.h"
#import "TableViewCell.h"
#implementation ViewController
- (void)dealloc; {
[_items release];
[super dealloc];
}
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad; {
[super viewDidLoad];
// This is an example of how to fill in the _items array with Models
_items = [[NSMutableArray alloc] init];
TableViewModel * model = [[TableViewModel alloc] init];
model.textFieldValue = #"1";
model.index = 0;
[_items addObject:model];
[model release];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField; {
TableViewModel * model = [_items objectAtIndex:_index];
model.textFieldValue = [_textField.text retain];
[_items replaceObjectAtIndex:_index withObject:model];
[_tableView reloadData];
[_textField resignFirstResponder];
return YES;
}
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; {
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; {
return 100;//This should be whatever the height of the cell is!
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; {
return [_items count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; {
NSString * cellIdentifier = #"TableViewCell";
TableViewCell * cell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil]; // hooks up _cell for us
cell = _cell;
}
cell.tableViewModel = ((TableViewModel *) [_items objectAtIndex:indexPath.row]);
return cell;
}
- (void)useTextFieldForIndex:(int)aIndex; {
_index = aIndex;
[_textField becomeFirstResponder];
}
#end
I assume that you know how to hook up the nibs, but if you need any more help, just ask. Also, you'll need to add these 2 methods to the AppDelegate.
+ (AppDelegate *)appDelegate; {
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
- (void)useTextFieldForIndex:(int)aIndex; {
[self.viewController useTextFieldForIndex:aIndex];
}
This will allow the AppDelegate to pass the actions to have the textfield actions in only one view controller. It also should help with performance. To give a bit of explanation, _items holds all of the models which are used in the tableview. (Side note: when you want the user to add a new cell, all you need to do is add a new model to this array.)
The action: - (IBAction)useTextField; is attached to a clear button, and when it is pushed, it tells the AppDelegate to tell the ViewController to bring up the keyboard, and once you are done with it, you update the model as the index of the cell that was pressed, and reload the tableview.
You can then customize the cells the way you want, and make sure that you match the models as well.
To add up the values in the Models, you need only use:
double sum = 0;
for(TableViewCellModel * model in _items){
sum += [model.valueOfTextfield doubleValue];
}
Hope that helps!

Custom UITableViewCells

I am actually very surprised how difficult it is to keep your code well structured and readable when doing iphone app stuff... but it might be because I am doing something wrong.
I have a Sign Up page containing different kinds of inline-editable data: birthday, gender, name, password, phone number. I have made the page as a table view of custom cells where each cell is an instance of a sub class of UITableViewCell and is read from its own nib file. This because I thought that I then might be able to reuse these different kinds of cells later in other table view pages.
The approach of encapsulating the different custom cells in their own place is not working that well though:
Who is going to be the controller of e.g the gender picker inside the GenderCell?
How am I actually going to reuse the cells in a different table view controller when I had to put the SignUpController as the file's owner of the cell nib files?
I do not know if anyone but myself understood what I just wrote, but if so, I would be very thankful for any suggestions on how to structure my code differently.
Thanks a lot,
Stine
To make things more clear (?!) let me paste some of my code in here:
EditableLabel.h
#interface EditableLabel : UILabel {
UIView *inputView, *inputAccessoryView;
}
#property (nonatomic, retain) UIView *inputView, *inputAccessoryView;
- (void) setInputView:(UIView *)aView andToolbar:(UIToolbar *)aToolbar;
#end
EditableLabel.m
#implementation EditableLabel
#synthesize inputView, inputAccessoryView;
- (void) dealloc {
[inputView release];
[inputAccessoryView release];
[super dealloc];
}
- (void) setInputView:(UIView *)aView andToolbar:(UIToolbar *)aToolbar {
self.inputAccessoryView = aToolbar;
self.inputView = aView;
}
- (BOOL) canBecomeFirstResponder {
return YES;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self becomeFirstResponder];
}
#end
EditableCell.h
typedef enum {
USERNAME, PASSWORD, MOBILE, BIRTHDAY, GENDER, DESCRIPTION, CATEGORY
} CellTag;
#interface EditableCell : UITableViewCell {
CellTag tag;
UIView *editPoint;
IBOutlet UILabel *headerLabel;
}
- (void) setTag:(CellTag)aTag andHeader:(NSString *)aHeader andEditPoint:(UIView *)aView;
#property (nonatomic) CellTag tag;
#property (nonatomic, retain) UIView *editPoint;
#property (nonatomic, retain) UILabel *headerLabel;
- (IBAction) editingDone:(id)sender;
- (void) showInputView;
- (void) hideInputView;
#end
EditableCell.m
#implementation EditableCell
#synthesize tag, editPoint, headerLabel;
- (void) dealloc {
[editPoint release];
[headerLabel release];
[super dealloc];
}
- (void) setTag:(CellTag)aTag andHeader:(NSString *)aHeader andEditPoint:(UIView *)aView {
self.tag = aTag;
self.headerLabel.text = aHeader;
self.editPoint = aView;
}
- (IBAction) editingDone:(id)sender {
[self hideInputView];
}
- (void) showInputView {
[self.editPoint becomeFirstResponder];
}
- (void) hideInputView {
[self.editPoint resignFirstResponder];
}
#end
EditableLabelCell.h
#interface EditableLabelCell : EditableCell {
IBOutlet UILabel *placeHolderLabel;
IBOutlet EditableLabel *editableLabel;
}
#property (nonatomic, retain) UILabel *placeHolderLabel;
#property (nonatomic, retain) EditableLabel *editableLabel;
- (void) setTag:(CellTag)aTag
andHeader:(NSString *)aHeader
andPlaceHolder:(NSString *)aPlaceHolder
andInputView:(UIView *)aView
andToolbar:(UIToolbar *)aToolbar;
- (void) setValue:(NSString *)aValue;
#end
EditableLabelCell.m
#implementation EditableLabelCell
#synthesize placeHolderLabel, editableLabel;
- (void) dealloc {
[placeHolderLabel release];
[editableLabel release];
[super dealloc];
}
- (void) setTag:(CellTag)aTag andHeader:(NSString *)aHeader andPlaceHolder:(NSString *)aPlaceHolder andInputView:(UIView *)aView andToolbar:(UIToolbar *)aToolbar {
[super setTag:aTag andHeader:aHeader andEditPoint:self.editableLabel];
self.placeHolderLabel.text = aPlaceHolder;
[self.editableLabel setInputView:aView andToolbar:aToolbar];
}
- (void) setValue:(NSString *)aValue {
if (aValue && aValue != #"") {
self.placeHolderLabel.hidden = YES;
self.editableLabel.text = aValue;
} else {
self.editableLabel.text = nil;
self.placeHolderLabel.hidden = NO;
}
}
#end
EditableGenderCell.h
#protocol EditableGenderCellDelegate <NSObject>
#required
- (NSString *) getTextForGender:(Gender)aGender;
- (void) genderChangedTo:(Gender)aGender forTag:(CellTag)aTag;
#end
#interface EditableGenderCell : EditableLabelCell <UITableViewDataSource, UITableViewDelegate> {
id<EditableGenderCellDelegate> delegate;
Gender gender;
IBOutlet UITableView *genderTable;
IBOutlet UIToolbar *doneBar;
}
- (void) setTag:(CellTag)aTag
andDelegate:(id<EditableGenderCellDelegate>)aDelegate
andHeader:(NSString *)aHeader
andGender:(Gender)aGender
andPlaceHolder:(NSString *)aPlaceHolder;
#property (nonatomic, retain) id<EditableGenderCellDelegate> delegate;
#property (nonatomic) Gender gender;
#property (nonatomic, retain) UITableView *genderTable;
#property (nonatomic, retain) UIToolbar *doneBar;
#end
EditableGenderCell.m
#implementation EditableGenderCell
#synthesize delegate, gender, genderTable, doneBar;
- (void) dealloc {
[delegate release];
[genderTable release];
[doneBar release];
[super dealloc];
}
- (void) setTag:(CellTag)aTag andDelegate:(id<EditableGenderCellDelegate>)aDelegate andHeader:(NSString *)aHeader andGender:(Gender)aGender andPlaceHolder:(NSString *)aPlaceHolder {
[super setTag:aTag andHeader:aHeader andPlaceHolder:aPlaceHolder andInputView:self.genderTable andToolbar:self.doneBar];
self.delegate = aDelegate;
self.gender = aGender;
[super setValue:[self.delegate getTextForGender:aGender]];
}
#pragma mark - Table view data source
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 2;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
switch (indexPath.row) {
case MALE:
switch (self.gender) {
case MALE:
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
default:
cell.accessoryType = UITableViewCellAccessoryNone;
}
break;
case FEMALE:
switch (self.gender) {
case FEMALE:
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
default:
cell.accessoryType = UITableViewCellAccessoryNone;
}
break;
}
cell.textLabel.text = [self.delegate getTextForGender:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark - Table view delegate
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.gender = indexPath.row;
[super setValue:[self.delegate getTextForGender:self.gender]];
[self.delegate genderChangedTo:self.gender forTag:self.tag];
[tableView reloadData];
}
#end
Have a look at my answer to How to make a UITableViewCell with different subviews reusable?.
You should back up your custom tableviewcell nib files with a custom class representing your cell and encapsulate logic in it for example your gender picker. If you need to inform some outside controller of the gender you can make use of the delegate pattern.
Custom Gender picker in a TableViewCell
Ok let's start with the nib file, looking like this:
view hierarchy, don't set the File's Owner...
...set instead the class of the table view cell of your custom class:
The custom class
As you can see the class is almost empty, only providing the segmented control as property
GenderPickerTableViewCell.h
#interface GenderPickerTableViewCell : UITableViewCell
{
UISegmentedControl *genderPickerSegmentedControl;
}
#property (nonatomic, retain) IBOutlet UISegmentedControl *genderPickerSegmentedControl;
#end
GenderPickerTableViewCell.m
#import "GenderPickerTableViewCell.h"
#implementation GenderPickerTableViewCell
#synthesize genderPickerSegmentedControl;
#pragma mark -
#pragma mark memory management
- (void)dealloc
{
[genderPickerSegmentedControl release];
[super dealloc];
}
#pragma mark -
#pragma mark initialization
- (void)awakeFromNib
{
// initialization goes here, for example preselect a specific gender
}
#end
The table view using our new cell
I'll provide only the necessary methods to make this work. The TableViewCellFactory class is just a nib loader like I posted in my referenced answer above. The genderPickerTableViewCellWithTableView is just a convenience class method to return that special kind of cell without too much boilerplate code
The last important thing to note is the configuration of the cell, this is kept simple, I just access the segmented control directly and add a target to it which informs this view controller about a change.
#pragma mark -
#pragma mark view lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
tableView.rowHeight = 100.0;
tableView.dataSource = self;
tableView.delegate = self;
}
#pragma mark -
#pragma mark UITableView methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *) tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)anIndexPath
{
GenderPickerTableViewCell *cell = [TableViewCellFactory genderPickerTableViewCellWithTableView:aTableView];
[cell.genderPickerSegmentedControl addTarget:self
action:#selector(genderPicked:)
forControlEvents:UIControlEventValueChanged];
return cell;
}
#pragma mark -
#pragma mark UISegmentedControl action
- (void)genderPicked:(id)sender
{
UISegmentedControl *segmentedControl = (UISegmentedControl *)sender;
NSLog(#"selected index: %d", [segmentedControl selectedSegmentIndex]);
}
I hope this helps a bit for the beginning.
This is the code you can use for bouncing:
-(IBAction)textFieldDidBeginEditing:(UITextField *)textField { //Keyboard becomes visible
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3];
self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y - 50, self.view.frame.size.width, self.view.frame.size.height);
[UIView commitAnimations];
}
Just set y accordingly an call it when editing begins.