I am trying to figure out the best approach for adding and managing a UISwitch to my UITableView's headers, and I've read several links so far on how best to use the UISwitch in a table: here, here and here. These links demonstrate using the UISwitch in the cell whereas I'm using them in a custom UIView for the header. That said, I would prefer to use tags to manage these objects but I'm not able to figure out why the viewWithTag approach is not working.
Side note: I was able to put the UISwitches into an NSMutableArray at run time and manage them that way, but I'd rather not be so verbose, manage bounds violations/indexes on the array or check for nil lists, etc... It is also not clear to me how I would do this using IBOutlets. This is why I'm trying the tag approach.
My goal is to use the switches to collapse / expand the rows in each of the sections which is why I've thought to tag and add UISwitches as sub views to the UIView that I return in viewForHeaderInSection. Then re-reference them later when I need to perform some logic to collapse the cells. Additionally, at run time I could have 1 or more sections so hard-coding the tag numbers is impractical. Here's the code for that method:
Assuming:
#define kSwitchTagRange 2000
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 44)];
// Add UISwitches and ensure that UISwitch doesn't already exist for this section...
UISwitch *switchView = (UISwitch*)[self.tableView viewWithTag:(kLayerSwitchTagRange + section)];
if (switchView == nil) {
// Create switch
switchView = [[UISwitch alloc] init];
double xOffset = self.tableView.bounds.size.width - switchView.frame.size.width;
switchView.frame = CGRectMake(xOffset,
7,
switchView.frame.size.width,
switchView.frame.size.height);
[switchView addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
// Should we tag the switch view?
switchView.tag = kSwitchTagRange + section;
}
// Add switch as subview
[view addSubview:switchView];
return view;
}
In switchChanged: I just reload the table's data:
- (void)switchChanged:(id)sender {
[self.tableView reloadData];
}
Finally as the table's data is recreated I attempt to retrieve the UISwitch and determine it's on/off state, then I return 0 for the number of rows in the section if OFF and some other number if ON:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger rowCount = 0;
UISwitch *switchView = (UISwitch*)[self.view viewWithTag:(kSwitchTagRange + section)];
if (switchView != nil && switchView.isOn == NO)
{
rowCount = 0;
}
else
{
// Row count is something other than 0
rowCount = 3;
}
return rowCount;
}
Unfortunately, this switchView is always nil.
I have a few guesses, but can't determine why this is happening.
- Guess 1: The UIView to which the switch I want was added is deallocated when the table's data was reloaded. It doesn't exist in memory and therefore can't be found searching by tag.
- Guess 2: I'm adding the UISwitch to the view object incorrectly (in many examples I've seen objects added to a UITableViewCell's contentView, however since I'm sending back a UIView in the viewForHeaderInSection: method, I'm not sure those examples apply here. addSubview should add any object to the tree.
Can anyone tell me why the viewWithTag method above would return nil? I'm leaning toward Guess #1 but haven't found any documentation that tells me the custom header UIView is deallocated at any time. The cells are re-used, but what about the section headers?
Lastly, I've read this post and while the recommendation on tag-use makes sense it seems to dislike the tag approach at all. Why not use tags if you don't find using them to be messy and they're being used intelligently? Why is the tag feature even available?
Really, I just want to know why the viewWithTag method returns nil in my case.
Cheers!