Channels ▼
RSS

Embedded Systems

Making Two-Way Tables in iOS


Go into IB and create an empty object. Save it as TempCell.xib, and let IB add it to the project. Click on the File's Owner element in the TempCell.xib window and use the Identity Tool inspector (Tools > Identity Inspector) to change the Class option from NSObject to TableTemp­Control. This specifies that our table controller is the delegate object for our table cells. From the Library window, drag and drop a UITableViewCell into the TempCell.xib window. Control-click on the Table View Cell element in the window, and from the window that appears, click on the New Referencing Outlet choice. Drag a connection to the File's Owner element in the window. Choose settingsCell from the pop-up menu that appears. What you have just done is forge the links that specify the delegate (TableTempControl) for any message from the cell, and that the instance of the cell is referenced by settingsCell. This makes the cell visible to our code.

Let's start displaying some content in the cell. In TableTempControl class, locate the cellForRowAtIndexPath method, and modify its code as in Listing Four:

Listing Four



// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    static NSString *CellIdentifier = @"Cell";

	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
		[[NSBundle mainBundle] loadNibNamed:@"TempCell" owner:self options:nil]; 
		cell = settingsCell; 
		settingsCell = nil;
	}
	
	// Fetch content for row label (day of week)
	NSDictionary *dictionary = [listOfRows objectAtIndex:indexPath.section];
	NSArray *array = [dictionary objectForKey:@"Content"];
	NSString *cellValue = [array objectAtIndex:indexPath.row];
	
	//Set text in label
	cell.textLabel.text = cellValue;
    
    return cell;
}

Notice how if cell is nil, this method generates a new instance of it by loading the nib file TempCell.xib. Otherwise, the table will reuse existing instances of the cell for faster scrolling efficiency. The listOfRows array is first accessed to get the section array, and the row value references the content from the appropriate array. The text string obtained is copied into the text property for the cell's textLabel. Build and run the project. If the app dies horribly, you have botched completing a link in IB or have misspelled the nib file name. Make any corrections, and try again. If all goes well, you now have the phrases "Morning," "Day." "Evening," and "Night" repeating in the table's rows. Now the text fields have to be added.

Go back into IB, and drag the icon for a UITextField from the Library window and drop it into the TempCell.xib window. Do this two more times. Use IB to arrange the fields and their sizes similar to that in the figure. Or, you can cheat and look at the frame sizes and positions in the example project. In the TempCell.xib window, click on the disclosure triangle adjacent to the Table View Cell element to reveal the three Round Style Text Field elements you just added. Control-click on each, and first drag a connection from the delegate to the File's Owner element. Control-Click on each of them again and from New Referencing Outlet, drag a connection to the File's Owner. In the pop-up menu that appears, choose timeField, heatingField, and coolingField for each field, respectively. That should tie the text fields in the cell's UI to our code. Now revise cellForRowAtIndexPath as follows in Listing Five:

Listing Five


// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    static NSString *CellIdentifier = @"Cell";

	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
		[[NSBundle mainBundle] loadNibNamed:@"TempCell" owner:self options:nil]; 
		cell = settingsCell; 
		settingsCell = nil;

		cell.textLabel.backgroundColor = [UIColor clearColor];

		timeField.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];	
		heatingField.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];		
		coolingField.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
		
	}
	
  	// Configure the cell's contents with regards to section and row
	// Fetch content for row label (day of week)
	NSDictionary *dictionary = [listOfRows objectAtIndex:indexPath.section];
	NSArray *array = [dictionary objectForKey:@"Content"];
	NSString *cellValue = [array objectAtIndex:indexPath.row];
	
	// Set text in cell label
	cell.textLabel.text = cellValue;

	// Set text in editable fields
	timeField.text = [NSString stringWithFormat:@"%@", [self.dateFormatter stringFromDate:[settings.timeOfDays objectAtIndex:((indexPath.section * 4) + indexPath.row)]]];
	heatingField.text = [NSString stringWithFormat:@"%@", [settings.heatStr objectAtIndex:((indexPath.section * 4) + indexPath.row)]];
	coolingField.text = [NSString stringWithFormat:@"%@", [settings.coolStr objectAtIndex:((indexPath.section * 4) + indexPath.row)]];
	
    return cell;
}

Study the code that extracts the relevant values from the arrays and places them into the text fields in the cell. The section value is used to calculate which object in the timeOfDays, heatStr, and coolStr arrays to access. The string fetched from the array is then placed in the text property of the corresponding text field. Items of interest are that we adjust the typeface size to ensure that text fits, and that the background color for the cell's textLabel is clear. The modification to the label's backgroundcolor property is required for the text fields to appear in the content area of the cell. I lost a few hours tracking down and resolving that quirk. Build and compile the app, and you should see the time and temperatures appear in the table.

But we're not done yet: If you click on a text field, the virtual keyboard appears and you can edit the text. However, it doesn't disappear when you click on the Return key. What is happening is that we have failed to designate a delegate for any UITextField action messages, and the message we want to catch is the one that informs us that the editing is done.

Making the TableTempControl class the delegate for the action messages is straightforward. Go to the TableTempControl's header file, and revise the interface line to appear as so:

@interface TableTempControl : UITableViewController <UITextFieldDelegate> {

Now a method is required to handle the action message generated when the user taps the Return key to signal the editing is done. This message is handled, per the UITextFieldDelegate_Protocol, by the method textFieldShouldReturn. Quickly we can write:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {

  [textField resignFirstResponder];
  return YES;
  
}

When a text field is tapped on, iOS makes the virtual keyboard that appears the first responder. That is, the keyboard object gets the first crack at handling any subsequent taps on the screen. This flow of events through the view hierarchy remains in force until the text field resigns its first responder status. The code above does that by sending a resignFirstResponder message to text field instance referenced by this method's textField argument. When you tap the Return key now, the keyboard is dismissed.

However, we are still not done: If you scroll the table up and down so that the edited fields disappear off-screen briefly, when they reappear they display the old values. The reason is that while we've altered the string in the text field, we haven't stored the change in the data model yet. Let's look into doing that.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video