Reputation: 927
I have got a dynamic form similar to contact form on iphone and ipad. A contact has "static" informations like last name, first name, address, ... And he also has "dynamic" informations like friends, Hobbies, whatever ...
So I created an UITableView
which is composed of difference types of cell like StaticInformationCell
, FriendCell
, HobbyCell
. Each type of cells has one or several UItextfield
regarding the informations it needs.
It works pretty well for self cell validation. I mean when the user edits the UITextField
of one particular cell, this one can valid or not the value and display or not the overview in the UITextField
.
My problem is that the UITableView
doesn't know if the entire form (all the cells) is valid when the user submits the form. I don't know how the UITableView
can "ask" each cell if it is valid or not.
I tried to store in a NSMutableSet
the cells when they were created and send a message isValid
to each cell. Unfortunetly I don't know why some cells are "duplicated in this" Set
:
<FriendEditCell: 0x8ddf9e0; baseClass = UITableViewCell; frame = (0 383; 768 70); alpha = 0; hidden = YES; autoresize = W; layer = <CALayer: 0x8db4010>>,
<FriendEditCell: 0x8dcfd80; baseClass = UITableViewCell; frame = (0 383; 768 70); autoresize = W; layer = <CALayer: 0x8d90920>>
I can't use a static UITableView
because an user can add as many friends as he wants.
Do you have an idea how I can fix my validation problem ?
Upvotes: 1
Views: 1412
Reputation: 927
Finally I refactor the way I validate my form.
I modified my model to include the logic validation. For example in the class Contact I have these methods :
- (NSString*)isFirstnameValid; // check length or unicity for example and return what's wrong in the current value
- (NSString*)isLastnameValid;
- (BOOL)isContactValid;
The two first methods are useful for live validation by the custom cells. (Add an overlay if needed)
The last one uses the two methods above and the same methods in each Friend
and Hobby
to know if all the contact's values are valid.
When the user submits the form I simply check [self.contact isContactValid]
before saving the data.
I like this way to do because validation logic is in the classes and can be reused in an other form for example.
Upvotes: 0
Reputation: 1677
You probably got cells repeated because of the UITableView Re-Use, i mean you may be allocating the cells again in cellForRowAtIndexPath:
which is not what you need.
To be understood, UITableView calls cellForRowAtIndexPath
: repeatedly while it scrolls for the same indexPath. Also, it implements Cell Re-Usability using identifiers, which is very good for minimum memory usage and smoothness while a huge set of data to be displayed.
But in a scenario like yours, I'll implement the following design pattern.
Write SubClasses of UITableViewCell for each kind of cell like FriendCell, HobbyCell etc.
Implement isContentValid
method in every class with appropriate implementation.
@interface StaticInformationCell : UITableViewCell
@end
@interface FriendCell : UITableViewCell
- (id)initWithFriend:(id)friend;
- (BOOL)isContentValid;
@end
@interface HobbyCell : UITableViewCell
- (id)initWithHobby:(id)hobby;
- (BOOL)isContentValid;
@end
Allocate needed cells as per your data models in viewDidLoad and keep in an Array
or Array of arrays
(in case of sectioned tableView)
@interface MyTableViewController ()
{
NSMutableArray *cells;
}
@end
- (void)viewDidLoad
{
[super viewDidLoad];
cells = [NSMutableArray array];
//Section0
StaticInformationCell * aStaticInformationCell = [[StaticInformationCell alloc] init];
[cells addObject: @[aStaticInformationCell]];
//Section1
NSMutableArray *friendCells = [NSMutableArray array];
for(Friend *friend in user.friends){
FriendCell *friendCell = [[FriendCell alloc] initWithFriend:friend];
//Set needed properties
[friendCells addObject:friendCell];
}
[cells addObject:friendCells];
//Section2
NSMutableArray *hobbyCells = [NSMutableArray array];
for(Hobby *hobby in user.hobbies){
HobbyCell *hobbyCell = [[HobbyCell alloc] initWithHobby:hobby];
//Set needed properties
[hobbyCells addObject:hobbyCell];
}
[cells addObject:hobbyCells];
}
Provide cells for the UITableView
directly from the cells array
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [cells count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[cells objectAtIndex:section] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Return the cell directly from array
return [[cells objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
}
Check overall validity
- (BOOL)allContentsValid{
//You should iterate through each cell and check overall validity
BOOL valid = TRUE;
for(id cell in cells){
if(![cell isContentValid]){
valid = FALSE;
break;
}
}
return valid;
}
You can dynamically insert new cells, for example to add more friends
- (void)addNewFriend{
Friend *newFriend = [[Friend alloc] init];
//[newFriend settheProperties:];
FriendCell *friendCell = [[FriendCell alloc] initWithFriend:newFriend];
//Set needed properties
[[cells objectAtIndex:1] addObject:friendCell];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:([[cells objectAtIndex:1] count] - 1) inSection:1];
[[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]];
}
Upvotes: 1
Reputation: 2027
If I understand the question correctly, and Im not entirely sure I do, I would subclass UITableViewCell, and make the custom cells of that type. for that cell I would create a "validate" method that checks the content of the uitextfield depending on what you call a "valid" cell. this function would return TRUE if the cell is valid. When submitting the form I would loop over all the cells and set some kind of flag to fall if one of the "validates" returns a false and stop the submit.
Upvotes: 1