Tutorial 3: iOS Shipment Tracker with Reminders

Marcio Valenzuela walks you through Part 3 of the coding process required to create shipment tracking app.

Sometimes the best way to learn is to do the work. When you reach the end of these tutorials you will have a working shipment tracking application for iOS.

Static Cells and TextFields

Now that we are ready to add Shipments, we have to modify the tableview we created in order to have it display only one cell. After all, we will only be adding one shipment at a time. For this we will use Static Cells instead of Dynamic Prototypes. A dynamic prototype is a cell that will be mass-produced dynamically (on the fly). A static cell is used to create one or a few individually distinct cells according to a limited set of requirements. For example, we only need one of said cells and they will not require dynamically changing data. Our unique cell only requires a textfield the user can fill in.

In storyboard, select the AddShipmentViewController tableview and switch from Dynamic Prototype cells to Static Cells. (Figure A)

Figure A


Delete the bottom two cells as you will not need them. Simply click on them and hit the delete key. Now to make it look more professional, set the table view style to "grouped" so your cell looks like Figure B.

Figure B


Now drag a Text Field control from the Object library into the cell and center it. Now let's size it up to be roughly the size of the cell itself and set it to Borderless so you basically cannot tell the Text Field is there. Notice we used a Text Field and that's because it's a control made to receive user input of varying size and it can respond to user interaction in a way Labels can't. So your cell now looks like Figure C.

Figure C


This is when that hierarchy view of your storyboard scenes and objects comes in handy. It should look like Figure D.

Figure D


This makes it clear that the AddShipmentVC contains the table view, which contains the section with a cell that contains the text field. Sometimes you will accidentally drop a text field or label outside of a cell and when you run the app you will go crazy trying to find it.

Run the app and notice that as soon as you tap on the text field (inside the cell) the keyboard slides in and you can type. However, also notice what happens if you tap on the right edge of the cell, where the text field ends and there is still a bit of cell left over. (Figure E)

Figure E


You tapped on the actual cell, so the cell is responding to its class method to respond to a tap by highlighting it blue. Let's disable it by adding this method to your AddShipmentVC .m file:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath


  return nil;


And go ahead and set the cell's Selection Style to None in the Attributes Inspector in the storyboard.

Now let's use another advanced XCode feature (as the Editor Embed In feature). Look at the top right (Figure F) and notice these buttons.

Figure F


I have the Standard Editor open but not the Assistant Editor nor the Version Editor. I also have the Navigator and Utilities pane open but not the Debug pane. We are going to use the Assistant Editor to create an outlet this time, but so it doesn't get so crowded we will close the Utilities pane. Go ahead and open the Assistant Editor. Since it is so crowded now, go on and close the Utilities pane. If you don't close the Utilities pane, your XCode window will look like Figure G.

Figure G


Go on and close the Utilities pane so you have more room to maneuver. If you want a cleaner look you can even close the Navigator pane on the far left. In any event, your AddShipmentVC should appear in storyboard and the Assistant Editor should have automatically selected the respective .h file and displayed it. Now the interesting part - Ctrl + drag from the text field in storyboard to the AddShipmentVC .h interface.

You will get a popup like Figure H.

Figure H


Note: Make sure to drag to the @interface of your AddShipmentViewController and not to that of the AddShipmentViewControllerDelegate protocol.

Notice it is trying to create a UITabelViewCell type outlet. That is no good! We are trying to create an outlet for the text field so we can access it in code and capture the user's input. Click cancel and make sure you select the text field control in the storyboard and repeat the Ctrl + drag operation. You want to see something similar to Figure I.

Figure I


When you drag correctly, the hierarchy pane shows you have correctly selected the text field. The storyboard shows the handles around the text field. Finally the popup displays this outlet will be of type UITextField.

Make sure the fields are set to these values:

  • Connection: Outlet
  • Name: textField
  • Type: UITextField
  • Storage: Strong

Press the Connect button and notice how it creates the property declaration. Don't forget to @synthesize your new property and set it to nil in the viewDidUnload method.

Change your AddShipmentVC done method to this:

- (IBAction)done:(id)sender


  NSLog(@"Contents of the text field: %@", self.textField.text);

  [self.delegate addShipmentViewControllerDidSave:self value:self.textField.text];


We slightly modified the delegate call to pass over the textField.text value. Thus we must modify the receiving method in ViewController to this (and log the value):

- (void) addShipmentViewControllerDidSave:(AddShipmentViewController *)controller value:(NSString*)value


  NSLog(@"The value received in VC is %@",value);

  [self dismissViewControllerAnimated:YES completion:nil];


This way we can receive the value and log it again. Don't forget to change the protocol method in AddShipmentViewController as well:

- (void)addShipmentViewControllerDidSave: (AddShipmentViewController *)controller value:(NSString*)value;

Now run the app and type in Shoes. Hit the Done button and watch how the console logs the value two times. Once in the AddShipmentViewController's Done method and again in the ViewController's addShipmentControllerDidSave method.

Perfect! So we have successfully received the user input in one viewcontroller object (vc object) into another vc object.


It's nice that when the user taps on the text field the keyboard pops up. But that's more useful when the user loads a screen with some text to read and text fields to fill in. In our case the only thing to do is fill in the text field thus it would be nice to simply present the keyboard as soon as the new screen comes into view. So look for and add this method to the AddItemViewController.

- (void)viewWillAppear:(BOOL)animated


  [super viewWillAppear:animated];

  [self.textField becomeFirstResponder];


Now in storyboard select the text field and make the following modifcations:

  • In placeholder set the value to "Shipment Name"
  • Set the Font to System 17
  • Scroll down and uncheck Adjust to Fit
  • Set Capitalization to Sentences
  • And set Return Key to Done

Additional features

There are many different options here you can play with. A very nice user-experience oriented feature is to make keyboards of the type of value you are entering into the text field. For example, if the user must enter a Zip Code, use a Numeric Keyboard. If the user will enter an email or URL then use the appropriate keyboard so the user doesn't have to frantically look for special symbols etc.

Finally, make sure the text field is selected and open the Connections Inspector. Drag from the Did End on Exit event to the view controller and pick the done action. This will fire the done selector when the user hits the Done button on the keyboard.

Another simple feature you can add by a simple click is the Auto-enable Return Key, which will automatically check the text field to make sure there is at least a value in the text field before allowing you to tap the Done button.

Okay, the next feature we will add is to check for valid data before clicking the Done button to return and dismiss the AddItemViewController. For that we need to make the view controller a delegate to the text field. The text field will send events to this delegate. The delegate, who will be our AddItemViewController, can then respond to these events and do what is appropriate.

So let's make sure our AddItemViewController interface line looks like this:

@interface AddItemViewController : UITableViewController <UITextFieldDelegate>

The AddItemViewController is now the delegate for text field objects in general. In this case we have to tell the text field object that the AddItemViewController is its delegate. So go to storyboard and select the text field. In the Connection Inspector, drag from "delegate" to the AddItemViewController dock, like shown in Figure J.

Figure J


Now open the Assistant Editor and Ctrl drag from the Done button to the AddItemViewController.h and name it doneBarButton. Add the corresponding synthesize statement in .m and set it to nil in the viewDidUnload method. Finally add this method to the AddItemViewController:

- (BOOL)textField:(UITextField *)theTextField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string


  NSString *newText = [theTextField.text stringByReplacingCharactersInRange:range withString:string];

  if ([newText length] > 0) {

  self.doneBarButton.enabled = YES;

  } else {

  self.doneBarButton.enabled = NO;


  return YES;


One last tweak

What we are doing here is getting the user input and placing it into a string. Then we check to see if it's empty and take the necessary action. The only problem is that if you run the app now, the Done button is initially enabled. If you go to storyboard and uncheck the Enabled Box of the text field then it will work perfectly!

Also read: