Writing to a label when creating a custom cell Xcode - iphone

I keep running into a problem when I try to write to a label in a custom cell. So right now, I have a class with a table view called "AccountViewController" and I have a class with my custom cell "AccountViewCell. I can get my cell to correctly display in my table, however I run into a problem when I try to link the label in my custom cell to their outlets and when I write to the labels.
Right now my code is:
AccountViewController.h
#import <UIKit/UIKit.h>
#import <GameKit/GKSession.h>
#import <GameKit/GKPeerPickerController.h>
#interface AccountViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
NSArray *tableData;
int cellValue;
NSString *cellContents;
}
#property (nonatomic, retain) NSArray *tableData;
#property (nonatomic, retain) NSString *cellContents;
#property (nonatomic, retain) NSString *accountSelected;
#property (nonatomic, retain) NSString *accountList;
#property (nonatomic, retain) NSString *amount;
#end
AccountViewController.m
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"AccountViewCell";
AccountViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"AccountViewCell" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [topLevelObjects objectAtIndex:0];
}
// cell.accountNameLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
AccountViewCell.h:
#import <UIKit/UIKit.h>
#interface AccountViewCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *accountNameLabel;
#property (nonatomic, weak) IBOutlet UILabel *accountNumberLabel;
#property (nonatomic, weak) IBOutlet UILabel *balanceLabel;
#end
AccountViewCell.m
#import "AccountViewCell.h"
#implementation AccountViewCell
#synthesize accountNameLabel = _accountNameLabel;
#synthesize accountNumberLabel = _accountNumberLabel;
#synthesize balanceLabel = _balanceLabel;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
Again, my code works fine and displays my custom cell when I don't try to set a label's text or connect the outlets to the labels in AccountViewCell as shown here:
http://i.imgur.com/TuFun5y.png
My cell Identifier is correct: http://i.imgur.com/ZbsDvaa.png
Now, the problem is when I connect the outlets like this: http://imgur.com/OOiKpkM
The code will break, even if I don't set or declare the labels in AccountViewController.m It gives me this error:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<AccountViewController 0x104b2220> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key accountNameLabel.'
*** First throw call stack:
(0x248e012 0x1d2be7e 0x2516fb1 0x815711 0x796ec8 0x7969b7 0x7c1428 0xd620cc 0x1d3f663 0x248945a 0xd60bcf 0xd6298d 0x28e54 0xbfff4b 0xc0001f 0xbe880b 0xbf919b 0xb9592d 0x1d3f6b0 0x287ffc0 0x287433c 0x2874150 0x27f20bc 0x27f3227 0x27f38e2 0x2456afe 0x2456a3d 0x24347c2 0x2433f44 0x2433e1b 0x29e37e3 0x29e3668 0xb4565c 0x49b2 0x2c45)
libc++abi.dylib: terminate called throwing an exception
I need a way to be able to write to the label. I've tried everything I could think of and read many threads, however I cannot figure this out. If someone could please help and could show me a way to write to a label in a custom cell, that would be great.

Ok, I figured it out. I should not have been linking the labels via file owner but instead via the table cell.

Related

Custom UITableViewCell Not Loading

I am creating my own custom UITableViewCell using interface builder. I am supporting iOS 5 & iOS 6 but I do not want to use Storyboard. Please do not suggest storyboard. I'm sticking to Interface Builder and writing programatically.
I created a class that subclasses UITableViewCell. Here's the .h file:
#interface CategoryCell : UITableViewCell
{
__weak IBOutlet UIImageView *image;
__weak IBOutlet UILabel *name;
__weak IBOutlet UILabel *distance;
__weak IBOutlet UILabel *number;
__weak IBOutlet UIImageView *rating;
}
#property (nonatomic, weak) IBOutlet UIImageView *image;
#property (nonatomic, weak) IBOutlet UILabel *name;
#property (nonatomic, weak) IBOutlet UILabel *distance;
#property (nonatomic, weak) IBOutlet UILabel *number;
#property (nonatomic, weak) IBOutlet UIImageView *rating;
#end
The XIB file is of type UIViewController and has a View of type CategoryCell. I connected the outlets as I have to.
The Problem
dequeueResuableCellWithIdentifier is not calling the custom cell. Here's what I have:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CategoryCell";
CategoryCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CategoryCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
.....
}
return cell
}
When I substitute the loadBundle line with: cell = [[CategoryCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];, it does work. But the nib does not load. So a cell loads, but not my own cell so I cannot set the labels and images that I want. When adding the regular load bundle line (as the sample above shows) and breakpoint the init method of the custom cell, it does not get called. Also, what I get is a full white screen that overrides the whole iPhone screen in the simulator.
Why's that happening? What am I doing wrong here? When I tried setting the outlets to strong (which I know I'm not supposed to), it does not work either.
EDIT:
I fixed it by replacing the NSBundle line with:
UIViewController *temporaryController = [[UIViewController alloc] initWithNibName:#"CategoryCell" bundle:nil];
cell = (CategoryCell *)temporaryController.view;
What is it that I've done wrong with the NSBundle method? Supposedly that's supposed to be the "easier" way to do it.
Have you ever try the registerNib method in tableview? It's very convenient for load nib start from iOS 5.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"CategoryCell" bundle:nil]
forCellReuseIdentifier:#"CategoryCell"];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CategoryCell";
CategoryCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
return cell
}
make sure you have define identifier in the CategoryCell.nib , it's under Attribute inspector! Hope this work.
The XIB file is of type UIViewController and has a View of type CategoryCell. I connected the outlets as I have to.
The problem in this is that the root object of your XIB need to be a UITableViewCell or a subclass of it.
And be sure to have your reuse identifier set in your XIB.

Use IBAction from UIButton inside custom cell in main view controller

I have created a custom cell with its own .m, .h and .xib file. In the cell, I have a UIButton that I added to the xib in IB.
I can receive the IBAction from the UIButton in this custom cell's .m, but really, I'd like to be forwarding that button press to the main view .m that is hosting the table (and so custom cell) and use an action there.
I've spent the last 4 hours attempting various ways of doing this - should I be using NSNotificationCenter? (I've tried Notifications lots but can't get it to work and not sure if i should be persevering)
You need to use delegate in .h file of cell.
Declare the delegate like this
#class MyCustomCell;
#protocol MyCustomCellDelegate
- (void) customCell:(MyCustomCell *)cell button1Pressed:(UIButton *)btn;
#end
then declare field and property
#interface MyCustomCell:UItableViewCell {
id<MyCustomCellDelegate> delegate;
}
#property (nonatomic, assign) id<MyCustomCellDelegate> delegate;
#end
in .m file
#synthesize delegate;
and in button method
- (void) buttonPressed {
if (delegate && [delegate respondToSelector:#selector(customCell: button1Pressed:)]) {
[delegate customCell:self button1Pressed:button];
}
}
Your view controller must adopt this protocol like this
.h file
#import "MyCustomCell.h"
#interface MyViewController:UIViewController <MyCustomCellDelegate>
.....
.....
#end
in .m file in cellForRow: method you need add property delegate to cell
cell.delegate = self;
and finally you implement the method from protocol
- (void) customCell:(MyCustomCell *)cell button1Pressed:(UIButton *)btn {
}
Sorry for my english, and code. Wrote it from my PC without XCODE
I had the same problem, and I solved it by subclassing the cell into it's own class, and put the buttons there as outlets, and filling the cell with data from the model, while using a method that returns the cell we're currently viewing.
For example, if you had a Person class, and each person had a name, a surname, and a number of friends. And each time you clicked a button in the cell, the number of friends for a specific person would increase by 1.
_______________DATA SOURCE___________________________
#import <Foundation/Foundation.h>
#interface Person : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *comment;
#property (nonatomic) NSInteger numberOfFriends;
+(instancetype)personWithName:(NSString *)aName Surname:(NSString *)aSurname;
#end
#import "Person.h"
#implementation Person
+(instancetype)personWithName:(NSString *)aName Surname:(NSString *)aSurname{
Person *person = [[Person alloc] init];
[person setName:aName];
[person setSurname:aSurname];
[person setNumberOfFriends:0];
return person;
}
#end
_____________________PERSON CELL________________________
#import <UIKit/UIKit.h>
#interface PersonCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *friendsNum;
#property (strong, nonatomic) IBOutlet UIButton *friendsBtn;
#property (strong, nonatomic) IBOutlet UILabel *nameLabel;
#property (strong, nonatomic) IBOutlet UILabel *surnameLabel;
#end
Personally I created a private NSArray to hold the names of my Person objects, and a private NSMutableDictionary to hold my Person objects, and I set the keys to be the names of the people.
_____________________PERSON TABLE VIEW________________________
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
PersonCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *name = [peopleNames objectAtIndex:indexPath.row];
Person *person = [people objectForKey:name];
if(cell == nil)
{
cell = [[PersonCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.nameLabel.text = person.name;
cell.surname.Label.text = person.surname
[cell.friendsButton addTarget:self action:#selector(moreFriends:) forControlEvents:UIControlEventTouchUpInside];
cell.friendsNum.text = [NSString stringWithFormat:#"%i", person.numberOfFriends];
return cell;
}
- (IBAction)moreFriends:(id)sender {
UIButton *btn = (UIButton *)sender;
PersonCell *cell = [self parentCellForView:btn];
Person *person = [people objectForKey:cell.nameLabel.text];
person.numberOfFriends++;
[self.tableView reloadData];
}
-(PersonCell *)parentCellForView:(id)theView
{
id viewSuperView = [theView superview];
while (viewSuperView != nil) {
if ([viewSuperView isKindOfClass:[PersonCell class]]) {
return (PersonCell *)viewSuperView;
}
else {
viewSuperView = [viewSuperView superview];
}
}
return nil;
}
I would recommend using a delegate.
You might want to just add a selector for the button in your view controller which has your tableview.
in your cellForIndexPath function
[yourCell.button addTarget:self action:#selector(customActionPressed:) forControlEvents:UIControlEventTouchDown];
then handle the button press in your "customActionPressed:(id) sender" method
//Get the superview from this button which will be our cell
UITableViewCell *owningCell = (UITableViewCell*)[sender superview];
//From the cell get its index path.
NSIndexPath *pathToCell = [myTableView indexPathForCell:owningCell];
//Do something with our path
This may be a better solution for you unless there are more factors that you haven't listed.
I have a tutorial which is might explain more http://www.roostersoftstudios.com/2011/05/01/iphone-custom-button-within-a-uitableviewcell/
Why not create a delegate (using #protocol) for your custom cell. You can then designate the main view as each cell's delegate and process the action appropriately.

Where/If to release properties in a UITableViewCell

EDIT: Ok, so i figured out how to remedy my original problem, but i'm not sure if this is the best way.
My new question is, say I have a subclass of UITableViewCell with the following property declaration in the header:
#property (nonatomic, retain) IBOutlet UILabel *levelLabel;
This is connected in IB. Is it ok to not release this in dealloc, and not release it at all? This is the only way I can figure out to get it to work, without giving me an exc_bad_access error. Before, it called dealloc when the tableviewcell went off the screen but then it still needed it. where do i release stuff, or does it take care of that for me?
Original Title: Memory leak in UITableView and exc_bad_access
Ok, I am confused. I was following along with this tutorial online making custom UITableViewCells. I made one, and i did everything like the tutorial told me. My UITableViewCell subclass contains 3 UILabels and 3 UIButtons, and has all of them defined as properties and connected in IB. I need them to be available to the class because i need to know when the buttons are pressed and be able to change the text. When I run the app, i start scrolling and after a few seconds it crashes, with exc_bad_access in main (no output in the console). But when I run the app in instruments with NSZombieEnabled, it does not crash at all, and runs just fine. However, since instruments shows you the allocations, i can see them going up very quickly, especially as I scroll. I dont know if this is all allocations, or if these are being released, but still it seems too fast.
Here is PointCoordinatesCell.h (my custom cell):
#import <UIKit/UIKit.h>
#interface PointCoordinatesCell : UITableViewCell
#property (nonatomic, retain) IBOutlet UILabel *levelLabelLabel;
#property (nonatomic, retain) IBOutlet UILabel *levelLabel;
#property (nonatomic, retain) IBOutlet UILabel *levelDescriptionLabel;
#property (nonatomic, retain) IBOutlet UIButton *beginningButton;
#property (nonatomic, retain) IBOutlet UIButton *developingButton;
#property (nonatomic, retain) IBOutlet UIButton *secureButton;
#end
PointCoordinatesCell.m:
#import "PointCoordinatesCell.h"
#implementation PointCoordinatesCell
#synthesize levelLabel, levelLabelLabel, levelDescriptionLabel, beginningButton, developingButton, secureButton;
- (void)dealloc{
[super dealloc];
[levelLabel release];
[levelLabelLabel release];
[levelDescriptionLabel release];
[beginningButton release];
[developingButton release];
[secureButton release];
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
RootViewController.h has nothing in it other than a class declaration and standard imports. No variables or methods defined. It subclasses UITableViewController.
RootViewController.m:
#import "RootViewController.h"
#import "StatesAppDelegate.h"
#import "PointCoordinatesCell.h"
#implementation RootViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 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]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 50;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
return 293;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"PointCoordinatesCell";
PointCoordinatesCell *cell = (PointCoordinatesCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"PointCoordinatesCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (PointCoordinatesCell *) currentObject;
break;
}
}
}
//cell.capitalLabel.text = [capitals objectAtIndex:indexPath.row];
//cell.stateLabel.text = [states objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:#"AnotherView" bundle:nil];
// [self.navigationController pushViewController:anotherViewController];
// [anotherViewController release];
}
- (void)dealloc {
[super dealloc];
}
#end
It seems you are doing some complicated casting in your cellForRowAtIndexPath method. I do not think this is necessary. It does not seem logical to me to check for an object of class UITableViewCell and then cast it into a custom cell. The cell in your nib should already be a custom cell.
In the Apple sample the loading of the cell is much more straight forward. You link your custom cell to an IBOutlet in your view controller and then do this:
CustomCell *cell = (CustomCell *) [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = customTableViewCell;
self.customTableViewCell = nil;
// etc.
}
No, it is not okay to not release the label. You declared the property with 'retain'-specifier. That means you will have to release it at least in dealloc (A safe way to do that is: self. levelLabel = nil;).
As you've noticed the memory consumption will raise during scrolling if you don't release the objects (memory leaks!).
You'll have to tell where the exc_bad_access error occurs so that we can help you ...

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!

Request for member 'uitextfield' in something not a structure or union?

working through several other problems I have found myself at this point. I have learnt alot about the stuff I am trying to do but this one I am completely stumped on.
I am writing a textfield format for a login I would like to have on my app, and because apple don't have anything that resembling a textfield mask I have decided to write my own custom cell that looks like it has a mask on it but all I will be doing is concatenating textfields in the background.
However I have struck a problem. I am trying to call textField:shouldChangeCharactersInRange:replacementString: of a UITextField in my Subclassed UITableViewCell as outlined in my code below. However Im receiving Request for member 'uitextfield' in something not a structure or union error... any help would be appreciated.
////.h
#interface RegisterDeviceViewController : UIViewController <UITableViewDelegate, UITextFieldDelegate> {
RegisterDeviceViewController *registerDeviceViewController;
//UITextFields for the registration cell
UITextField *regFieldOne;
UITextField *regFieldTwo;
UITextField *regFieldThree;
UITextField *regFieldFour;
UITableViewCell *myRegistrationField;
UITableViewCell *mySubmitButton;
}
//UITextFields for the registration cell
#property (nonatomic, retain) IBOutlet UITextField *regFieldOne;
#property (nonatomic, retain) IBOutlet UITextField *regFieldTwo;
#property (nonatomic, retain) IBOutlet UITextField *regFieldThree;
#property (nonatomic, retain) IBOutlet UITextField *regFieldFour;
#property (nonatomic, retain) IBOutlet UITableViewCell *myRegistrationField;
#property (nonatomic, retain) IBOutlet UITableViewCell *mySubmitButton;
#end
/////.m
#import "RegisterDeviceViewController.h"
#implementation RegisterDeviceViewController
//Custom registration cell fields
#synthesize regFieldOne;
#synthesize regFieldTwo;
#synthesize regFieldThree;
#synthesize regFieldFour;
#synthesize myRegistrationField;
#synthesize mySubmitButton;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
self.title = #"Registration";
[super viewDidLoad];
}
//Sets number of sections in the table
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
// Sets the number of rows in each section.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
//Loads both Custom cells into each section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"mythingy"];
if (cell == nil) {
cell = myRegistrationField;
}
UITableViewCell *cellButton = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"mummy"];
if (cellButton == nil) {
cellButton = mySubmitButton;
}
if (indexPath.section == 0) {
return cell;
cell.regFieldOne.delegate = self; //This is where the error is.
}
return cellButton;
}
//This delegate method is not being called.
//textField:shouldChangeCharactersInRange:replacementString:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
int length = [regFieldOne.text length] ;
if (length >= MAXLENGTH && ![string isEqualToString:#""]) {
regFieldOne.text = [regFieldOne.text substringToIndex:MAXLENGTH];
return NO;
}
return YES;
}
..........
regFieldDone is not a member of cell (table view cell). Its a member of your class register device view controller. If you are trying to set regFieldDone's delegate to self, then change that statement to regFieldDone.delegate = self
EDIT: You can directly set all text field's delegate to RegisterDeviceViewController (file owner) from the xib file.
You have only set regFieldDone's delegate to self, what about other textField's delegate? So when you edit other textField's, the delegate method will not get called.
You should notice that shouldChangeCharactersInRange... method gets called while editing regFieldDone and doesnt while editing other textField's. I advice you to set all textField's delegate to self, either programatically or from xib file.