Show input from textfields in a table - iphone

In the app I'm making I need to be able to store input from textfields, then show them in a table view with the ability, for the user, to delete or edit the input, and add more.
I have already made it possible to press a button -> next view, insert numbers and choose whatever option you want, and then press ADD. But I have no idea how to store and show the input.
The app is supposed to work this way:
You open the app, and you can press a PLUS sign. Then you are taken to a modal-view where get the option to choose from a slider, and input two different numbers in two textfields. Then press ADD. After the ADD-button is pressed, you are then taken to the first view, and the numbers and option you chose from the slider are then shown in a table view, with yet another plus sign beneath. So you can repeat the whole thing over and over.
After the above, there will be a "Calculate" button, where it calculates the different inputs, and gives an end result, but I will try and figure that one out myself, when I get the basic stuff working.
I'm looking forward to your answers, and I hope you will explain things thoroughly, as I am new at this field.
And please, don't just redirect me to , I have read a lot, but nothing that covered my problem. And I'm not that good at figuring out things myself, based on e.g. Apple's own reference library .

You are going to need someway to store all that info. If you need to sort or query against it in any way, use SQLite or you could use Core Data, but I never have.
More simply, you could instantiate an NSMutableArray, and make it property of the parent view, and when you push the child view to add the info, add a custom object that holds your info, and add it to the array. Tables are quite easy to use with array's, then implement the table methods to rearrange and delete them.
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
As far as calculating out totals or whatever, just loop through all the objects in that array, and do whatever you need to.
EDIT:
Example of a custom class:
MyClass
#property (nonatomic, retain) NSString *infoString1;
#property (nonatomic, retain) NSString *infoString2;
#property (nonatomic) int sliderValue;
How you could store the info
MyClass *object1 = [[MyClass alloc] init];
object1.infoString1 = textField.text;
object1.infoString2 = textField2.text;
object1.sliderValue = [theSlider.value intValue] //Dont think thats correct code, but you get the idea
[parentView.theArray addObject:object1];
// then dismiss the view

Related

A Question about Assign Properties

Edit 2: What I previously planned was probably a bad idea and I now changed my design: My UITableViewController has an array with all the values of my UITextFields and I am using delegation to update the values in the array. (If a value in one UITableViewCell changes, I send a message with the new value and the index of the cell).
Original Question
I would like to create a UITableViewCell subclass. To access my cells, I would like to have an NSMutableArray in my UITableViewController with all the cells. Whenever I create a new cell in - tableView:cellForRowAtIndexPath: I would add it to the array. The cells should however know about this array. I would declare a property like this for the UITableViewCell:
#property (nonatomic, assign) NSMutableArray *cellsArray;
Whenever I create a new cell, I would set its cellsArray to my array.
My (probably simple) question is: Is it correct that cellsArray will hold a pointer to the array in the UITableViewController and when I add stuff to the array of the UITableViewController, the cells will know this too, i.e. can access it?
Edit: The UITableViewCells contain UITextFields. I used to rely on the -cellForRowAtIndexPath: method and the visibleCells array, however when the cells moved out of view, the content of their UITextFields would also be lost. I then decided to store the cells in an array. When the user taps save, I iterate through the array and store the values. Also, I would like to automatically update the enabled property of the save button, depending on whether all cells contain something - for this I need all cells, too.
The cells should know about the other cells so that they can select the next cell when the return/next key on the keyboard is pressed.
If there are better approaches to this, I am glad to hear about them!
Not a direct answer of your question, but this sounds like a very bad design. Why should one cell need to know about its siblings? Any event/change that occurs in one cell and has an effect on the other cells should be handled by the table view controller. The single cells should be separate entities that should have no need to know about the state of each other.
Secondly, there is no need to introduce another array to manage the table cells. The table view already has a property visibleCells that you can access from the table view controller. And should never have to interact with invisible cells anyway because those are managed by the table view and its reuse facility.
I believe the answer is Yes.
My understanding of assign is that you can assign a value to such a variable and the retain count for the original object is not incremented. Similarly you need not release the variable in the object's dealloc method. You may run the risk, however, that the original array goes away and then cellsArray is pointing at something that is no longer there.
I use assign when I want to pass a reference to an object to another object (e.g. a view controller that is going to display or otherwise manipulate the object). And in the latter object, I do not release it's pointer to the object.
You also see assign used with properties that are id's, like
#property (nonatomic, assign) id<SomeProtocol> _myDelegate;
All that being said, with the exception of the id case, often I feel "safer" using retain for the property and being sure to release in dealloc. :-)
Anyway, I think that's the crux of the difference.

Objective-C (iOS) Access UITextField's text from another class

this question is extremely basic and I apologize if the answer should be staring me in the face.
So: I have a UITableView and another viewController. I'm updating some information for CoreData in the UITableView's .m file. In order to do this I need the text in a text field in the other viewController.
So being rather inexperienced, I tried:
[entity setName:[NSString stringWithFormat:#"%#", viewController.entityNameInputField.text]];
I've renamed a few things for clarity. Entity is my entity (no kidding), the attribute I'm setting is called Name, viewController is where the textField is and the text field is called entityNameInputField.
I'm a lot more interested in why this sort of thing doesn't work than what the solution to my problem might be. Why can't I just get the text from the text field in this way?
I suppose to word everything differently:
If I'm in Class A and I want to access the value of say, an NSString in class B, why can't I just use ClassA.TheString or [ClassA TheString] .... from what I've managed to understand, I'm sending these objects getter methods and I can't seem to see why this doesn't work...
Any help would be appreciated :)
Some more code would be useful to see what might be causing your confusion, but if you have declared properties in your classes the associated instance variables (or have manually declared accessors) then you will be able to access the associated ivars.
So, something like this (below) will work fine.
MyClassA * instanceOfA = [[myClassA alloc] init];
MyClassB * instanceOfB = [[myClassB alloc] init];
instanceOfA.myProperty = instanceOfB.myProperty;
As far as I understand, this is not a problem of accessing values from another class. Assuming that both view controllers are retained in memory, you can always call each other's getters/setters.
I assume that you've got a UITableViewController named A and then you're presenting a custom UIViewController named B with a text field. The user taps something in the text field and you want this text to go back to your table view controller. If inside B you have a valid reference to A, you can then call it's setter for the appropriate variable, and then dismiss the custom controller.
For example, in B's header you could have:
#interface MyViewController : UIViewController {
id tableViewController;
}
#property (nonatomic, retain) id tableViewController;
then in A, when you're creating B:
MyViewController *B = [[MyViewController alloc] init];
B.tableViewController = self; // this passes a reference to A
so when you're in B and the user has entered input in the text field, you could do something like
[self.tableViewController setVarname:textField.text];
assuming there's a varname variable in A, and a textField in B.
You can also gain access to A without having to create a separate variable, by calling
[self parentViewController]
if that suits you better.

Effective way to design and manage iPhone application similar to settings

I would just like to clarify that by 'design', I mean software design, not UI design.
I have an application similar to the native settings app. The problem I have with it is it doesn't follow the same clear-cut MVC style. Other apps tend to focus around displaying one kind of thing. In the case of a periodic table app for example, it's elements. The elements clearly comprise the model, and they share similar properties and behaviours, meaning they can be displayed and interacted with identically. An app like this almost designs itself!
My app, like the settings apps, consists of an arbitrary selection of rows displaying dissimilar data in dissimilar ways. One row might contain a switch, the other might modally present a very specific view when tapped. They're all very different.
How do you design something like this?
At the moment, I'm doing it all in the view controller, and the relevant rows are being tracked via an enum:
enum {
kNameRow,
kGenderRow,
kJobTypeRow,
kLevelOfExerciseRow,
kEmailAddressRow,
kTelephoneNumberRow
};
As I described, these cells are all very different, so displaying cells is handled like this:
// - tableView:cellForRowAtIndexPath pseudocode.
switch (indexPath.row) {
case kNameRow: // create name cell.
case kGenderRow: // create gender cell.
case kJobTypeRow: // create job type cell.
case kLevelOfExerciseRow: // create level of exercise cell.
case kEmailAddressRow: // create email address cell.
case kTelephoneNumberRow: // create telephone number cell.
}
And interacting with cells is handled similarly:
// - tableView:didSelectRowAtIndexPath pseudocode.
switch (indexPath.row) {
case kNameRow: // do name-specific stuff.
case kGenderRow: // do gender-specific stuff.
case kJobTypeRow: // do job type-specific stuff.
case kLevelOfExerciseRow: // do level of exercise-specific stuff.
case kEmailAddressRow: // do email address-specific stuff.
case kTelephoneNumberRow: // do telephone number-specific stuff.
}
This seems hugely unwieldy, and has the added of problem of not working when the table is broken down into multiple sections.
Is there a better way to do this? Are there any design patterns I would benefit from using when working with big tables of largely unrelated data?
Any tips at all are hugely appreciated.
I've become fond of implementing section controllers that pull the logic out of you UITableViewController subclass (or other hosting controller) and move them into self-contained classes.
I ended up implementing a base protocol that defines what a section controller needs to do - for me, that includes the number of rows in a section and a cell for the row (don't need the whole index path since the controller deals with a single section). I've got optional method for returning a section name and row height. That's all I've implemented so far since that's all I've actually needed.
It works for me because my individual sections tend to be homogeneous, but you could easily use the idea to return heterogeneous cells within the same section or refactor the idea to have cell type controllers instead of section controllers. In the end, my UITableViewDelegate and UITableViewDataSource methods just need to figure out which section controller to call instead of embedded all the logic within the UITableViewController subclass.
I think I got the idea from this article, but I also saw a more recent article that describes the same idea.
you might want to look at coreyfloyds project http://github.com/coreyfloyd/Generic-Heterogeneous-Table-Views i think this might have the functionality you need.
Here's my suggestion - handle each cell as a member of the view.
lol, it's been a while since I've used a table, so I could just be talkin' crap here but give it a try.
instead of an enum use:
NSThingyCell *nameRow;
NSThingyCell *genderRow;
#property IBOutlet NSThingyCell *nameRow;
#property IBOutlet NSThingyCell *genderRow;
- (IBAction) nameRowChanged:(id)sender;
- (IBAction) genderRowChanged:(id)sender;
and then instead of a table call with a switch, just wire each individual cell up in Interface Builder.
This has the added benefit of being row-independent, so if you have to put "ageRow" in between name and gender, nothing gets screwed up.
This will also get pretty big, so if your view has several tables, you may want to consider splitting those tables out into separate nibs/controllers and loading the views at run-time.
Have you ever thought of simply having an array of objects for a class which contains a UI element and some other identifiable data?
#interface settingsOption {
NSString *key;
UIView *displayElement;
}
+ (settingsOption *)optionWithKey:(NSString *)key andDisplayElement:(UIView *)displayElement;
#property (nonatomic, retain) UIView *displayElement;
#property (nonatomic, retain) NSString *key;
#end
Where the class method would look like
+ (settingsOption *)optionWithKey:(NSString *)key andDisplayElement:(UIView *)displayElement;
settingsOption *option = [[settingsOption alloc] init];
option.key = key;
option.displayElement = displayElement;
return [option autorelease];
}
Your settings class would have an array of settingsOption instances.
- (void)somewhereInMySettingsClass
mySettings = [[NSMutableArray alloc] init];
[mySettings addObject:[settingsOption optionWithKey:#"age" andDisplayElement:[UIButton buttonWithStyle:UIButtonStyleRect]]];
[mySettings addObject:...];
}
The table's cellForRowAtIndexPath would just do
[cell addSubview:[[mySettings objectAtIndex:indexPath.row] displayElement]];
You were talking about sections, though, which would add another layer to the data. This might simply be a matter of splitting mySettings into an array of arrays instead, where each array in the array is one section.
Not sure if I missed anything above. Feel free to point and poke.
You might simplify the settingsOption class further by adding more helper classes for various types of elements, e.g.
+ (settingsOption *)buttonWithKey:(NSString *)key;
+ (settingsOption *)switchWithKey:(NSString *)key;
+ (settingsOption *)pickerWithKey:(NSString *)key withDataSource:(id <UIPickerViewDataSource>)source withDelegate:(id <UIPickerViewDelegate>)delegate;
etc etc.

Setting ivar in objective-c from child view in the iPhone

Maybe a FAQ at this website.
I have a TableViewController that holds a form. In that form I have two fields (each in it's own cell): one to select who paid (single selection), and another to select people expense is paid for (multiple selection).
Both fields open a new TableViewController included in an UINavigationController.
Single select field (Paid By) holds an object Membership
Multiple select field (Paid For) holds an object NSMutableArray
Both vars are being sent to the new controller identically the same way:
mySingleSelectController.crSelectedMember = self.crPaidByMember;
myMultipleSelectController.crSelectedMembers = self.crSelectedMembers;
From Paid for controller I use didSelectAtIndexPath method to set a mutable array of Memberships for whom is paid:
if ([[tableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark) {
[self.crSelectedMembers removeObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
else {
[self.crSelectedMembers addObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
So far everything goes well. An mutable array (crSelectedMembers) is perfectly set from child view.
But...
I have trouble setting Membership object.
From Paid By controller I use didSelectAtIndexPath to set Membership:
[self setCrSelectedMember:[crGroupMembers objectAtIndex:indexPath.row]];
By NSlogging crSelectedMember I get the right selected member in self, but in parent view, to which ivar is pointed, nothing is changed.
Am I doing something wrong? Cause I CAN call the method of crSelectedMembers, but I can't change the value of crSelectedMember.
If I understand your question, the most likely cause is an improper property declaration.
If you want to pass values from one object to another using each objects properties, then you need to make sure to use assign to ensure the properties in one object are pointing at the same instances as the property in the other object.
So in your topViewController you have a property:
#property (nonatomic,retain) NSString crSelectedMember;
Then in your child view controllers you have:
#property (nonatomic,assign) NSString crSelectedMember;
This forces the value into the exact object in the parent controller.
However, this is a very fragile way to pass data between viewControllers. As your app becomes more complicated, it will be impossible to track all the passed data. (Worse, if you run into memory limitations, the parent view controller may unload and not even exist when you try to pass data to it.)
Instead, you should have a single custom object devoted to holding your data. Each view controller should query that object for the data it needs and should write any changes back to that object. The view controllers never communicate directly. This technique allows you to control the data in one specific location instead of spreading it out all over your code and it scales well. You can add an arbitrary number of view controllers to you app without having to worry about tying them all together.
See this post for details: iPhone: How to Pass Data Between Several Viewcontrollers in a Tabbar App

Count method of subclass of NSMutableArray crashes app

This seems to be a common problem, but I can't figure out anything from the answers I've seen so far. I have an iPhone app that uses a subclass of NSMutableArray to store objects, plus some additional properties. The subclass is skhCustomArray. The subclass initializes fine, with no objects in the skhCustomArray, and I assign it to the the property of my view controller, which is a pointer to an skhCustomArray.
prescriptionListVC* newPrescList = [[prescriptionListVC alloc] initWithNibName:#"PrescriptionList" bundle:nil];
newPrescList.curPersonPrescriptions = [personDetails objectAtIndex:0];
That works fine. Yet when I push my view managed by my view controller onto the navigation controller stack, the count method in the numberOfRowsInSection method crashes the app, see below.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [curPersonPrescriptions count];
}
What could be causing this? How can a valid custom array, with no objects, not return a valid count? Where am I going wrong? Thanks.
Subclass of NSArray? You're aware that NSArray is a class cluster, and is therefore somewhat difficult to subclass, right? In fact, it's so fraught with danger that the NSArray documentation has a whole section dedicated to what you need to do in order to subclass it.
I'll bet that that's the source of your woes.
You almost certainly don't need to subclass NSMutableArray in this situation. Instead, make a new class which has an array as a property, along with the extra properties you desire.
When you subclass NSMutableArray, you need to implement some mandatory methods like count, addObject:, insertObjectAtIndex etc. This is what we call as class cluster.
If you want to add some more feature/behavior to already implemented object then you can write a "category" instead of "subclassing" it.
If you want to subclass it, then you have to implement all those methods which your are going to use so better write a category of NSMutableArray and extend the feature what you want and use the NSMutableArray object only. This will solve your problem and also this is the easy and almost right way to add new behavior to already existing class.