Do you have an idea for an app but lack the programming knowledge to begin building it? In this weekly blog series, How To Unleash Your Inner App Developer, I will take you, the non-programmer, step by step through the process of creating apps for the iPhone, iPod Touch, and iPad. Join me each week on this adventure, and you will experience how fun turning your ideas into reality can be! This is Part 9 of the series. If you're just getting started now, check out the beginning of the series here.
In my previous post, I taught you how to write your very first line of code. In the process, I touched on the concept of passing messages in Objective-C. In this post, we're going to take a closer look at the important concept of passing messages, and we will also work on converting the prototype iAppsReview into a fully-functional app.
Reviewing Terminology
When you're a newcomer to programming, the terminology can be a bit overwhelming. To help you out, let's review some of the important terms you learned in the past few posts. As you review each term, use Figure 1 as a visual reference point.
- Framework - A set of tools you can access from within your app. For iOS app development, Apple provides Cocoa Touch, which is a set of frameworks (some of which are shown on the left side of Figure 1) that each provide functionality and services for your app. The Foundation Framework shown in the center of Figure 1 contains core functionality required by all iOS apps;
- Class - A class is like a blueprint that defines the attributes and behavior of objects. For example, the UITextField class shown on the right side of Figure 1 is part of the Foundation Framework and is the blueprint for all text-field objects in your app;
- Property - Defines a characteristic of a class. Classes usually have several properties. For example, the UITextField class has properties such as background, font, and text;
- Method - Defines the behavior of a class. A method groups one or more lines of code that are executed as a unit. Classes usually have several methods. For example, the UITextField class has methods such as clearButtonRectForbounds:, drawTextInRect:, and editingRectForBounds:;
- Object - A class that has "come to life." You can create multiple objects from a single class. For example, the bottom-right corner of Figure 1 shows three text-field objects created from the UITextField class.
Figure 1 - An overview of frameworks, classes, properties, methods, and objects |
Now that we have reviewed the basic terminology, let's talk about messages.
Messages 101
To run a specific method on an object, you pass a message to the object requesting it to run that method. For example, in Figure 1, the stringByAppendingString: message is passed to the myString object, and it returns an appended string:
Figure 2 - Passing the stringByAppendingString: message to a string object |
The act of sending a message to an object is known as a message call. Figure 3 illustrates the anatomy of a message call.
Figure 3 - The anatomy of a message call |
Here are the key things to note:
- A message call begins with a left square bracket and ends with a right square bracket;
- The object you are sending the message to is known as the receiver;
- The message can be broken down into two parts:
- The selector is the name of the method;
- An argument is a piece of data sent to the method.
To demonstrate another example of this, Figure 4 shows the anatomy of the message call you created in my previous post.
Figure 4 - The anatomy of the dismissviewControllerAnimated:completion method call |
Here are the key things to note:
- In this example, self (the view controller) is the receiver object;
- dismissviewControllerAnimated:completion: is the full name of the method (this is discussed in the next section);
- There are two arguments passed in this message, YES and nil.
The syntax of passing messages in Objective-C is a bit unusual, and even trips up seasoned developers coming from other C-based languages such as Java, C#, and C++.
Method Names in Objective-C
In Objective-C, method names are camel cased, meaning the first letter is always in lower case, and the first letter of each word in a compound word is uppercased (like a camel's head and its humps).
In Figure 4, there are two arguments passed in the message call. Notice there is a completion: description before the second argument. This description helps document what the argument is used for. In this case, the description completion: tells you that the code you pass is executed upon completion of the view controller being dismissed. In Objective-C, a method name includes all keywords including colons and argument descriptions. That's why dismissViewControllerAnimated:completion: is the full name of the method.
Two Kinds of Methods
In Objective-C there are two main types of methods—instance methods and class methods. Instance methods are called on objects—meaning you create an object from a class and then pass a message to the object. In contrast, class methods belong to the class itself, meaning you pass the message to the class directly without creating an object from the class.
All of the methods you have seen so far have been instance methods. Let's use the NSURL class to demonstrate how to call a class method. The NSURL class has a variety of methods for working with URLs (uniform resource locators, or character strings that reference an Internet resource or a local file on an iOS device). Typically, a URL is a web address that points to a resource such as a website, HTML page, or image. In iOS apps, you work with NSURL objects rather than with simple URL strings, so you often need to convert a simple string to an official NSURL object. The NSURL class has a URLWithString: method that allows you to do this. You pass the class method a string, and it returns an NSURL object.
Figure 5 shows the anatomy of a message call to the URLWithString: method of the NSURL class.
Figure 5 - Anatomy of a class method call |
Here are the key things to note:
- The receiver is the NSURL class, not an object;
- URLWithString: is the selector. This method accepts a string argument (Apple's website is passed in this example), which it converts to an NSURL object;
- The NSURL object that is returned from the URLWithString: method is saved in a variable named myURL.
Figuring Out How to Pass a Message
As you write code for your app, you are going to call many methods on many Cocoa Touch classes and objects. Maybe you need to send a text message, find the user's current location, or get the current user's high score in a game. It's one thing to figure out which class and method to call. It's another hurdle to figure out how to call that method. I'd like to demystify this process for you and break it down into steps.
Steps for Calling an Instance Method
Here are the main steps for calling an instance method on an object:
- Create the receiver object (the object you are passing a message to), if the object isn't already created;
- If there is a return value:
- Create a variable to hold the return value (you can name it whatever you want);
- Type "=" to store the return value into the variable.
- Type a left square bracket to start the message;
- Type the name of the variable that holds the receiver object;
- Type a space and then the name of the method to be called;
- If there are any arguments:
- Type a colon and then the first argument value;
- Do the same for any additional arguments.
- Type a right square bracket to end the message;
- Type a semicolon to end the statement.
You can refer back to these steps any time you need to call a method on an object.
Steps for Calling a Class Method
Here are the main steps for calling a method on a class:
- If there is a return value:
- Create a variable to hold the return value (you can name it whatever you want);
- Type "=" to store the return value into the variable.
- Type a left square bracket to start the message;
- Type the name of the class you are sending the message to;
- Type a space and then the name of the method to be called;
- If there are any arguments:
- Type a colon and then the first argument value;
- Do the same for any additional arguments.
- Type a right square bracket to end the message;
- Type a semicolon to end the statement.
These steps are very similar except you don't need to create an object from a class, and you send the message to the class itself, rather than to an object.
Interpreting Apple's Documentation
Apple provides documentation for all of the classes in the Cocoa Touch framework. I'm going to teach you how to interpret this documentation so you can know how to pass messages to objects and classes.
Figure 6 shows Apple's documentation for the NSString class. Notice that in the Table of Contents, the left side of this image, there is one entry for Class Methods and another entry for Instance Methods. This makes it easy for you to determine the type of a particular method.
Figure 6 - The NSString Class Reference documentation |
If you expand the Instance Methods node, you will see dozens of methods. If you click on the stringByAppendingString: method you will see the documentation shown in Figure 7.
Figure 7 - stringByAppendingString: documentation |
At the top of the image you can see the description that says "Returns a new string made by appending a given string to the receiver." This means that when you pass the stringByAppendingString: message to a string object (the receiver of the message) the string object appends the string you passed in the message to its own internal string value and returns the resulting string to you.
Directly below this description, the documentation describes the stringByAppendingString: method. This is known as the method signature:
- (NSString *)stringByAppendingString:(NSString *)aString
Here are the key things to note:
- The minus (-) sign is used in Objective-C to indicate that a method is an instance method;
- The value in parentheses indicates the type of the return value. In this case, it indicates this method returns a value of type NSString;
- stringByAppendingString: is the name of the method;
- The method accepts a single parameter whose type is NSString.
You often see the terms argument and parameter used interchangeably. An argument is a piece of data that you pass to a method. A parameter is a part of the method declaration that dictates the argument(s) to be passed to the method. In short, arguments appear in message calls, parameters appear in method declarations.
Now let's take a look at Apple's documentation for a class method. Figure 8 shows the documentation for the URLWithString: class method of the NSURL class.
Figure 8 - URLWithString: documentation |
We have already discussed what this method does, but I'd like you to take a look at the method signature. Here are the key things to note:
- The plus (+) sign is used in Objective-C to indicate that a method is a class method;
- The value in parentheses indicates the type of the return value. In this case, it indicates this method returns a value of type id. As you have learned, id means "any object." However, if you look further down in the documentation under Return Value, it says the method returns an NSURL object. Any time you know the type of the value returned from a method, you should use it instead of the generic id type;
- URLWithString: is the name of the method;
- The method accepts a single parameter whose type is NSString.
As we continue in this blog series, you will see many different method signatures, but the information in this post should help you decipher a wide variety of instance and class methods.
Let's Send Some Messages—Hiding the iOS Keyboard!
Now that I've laid out the basics of Objective-C messaging, let's go back to iAppsReview and add some functionality to the app by sending messages.
Note: To follow the instructions in this post, you must first download the latest version of iAppsReview from this link. If you run into trouble while following the steps in this post, you can get the completed (so far) version of iAppsReview from this link.
Our first job is to fix the Write Review scene so the keyboard is hidden when the user taps the background or taps the return key (in the text field only). Remember, when adding custom code for a scene, there are three key steps in the process:
- Add a new view-controller class to the project;
- Associate the new view-controller class with the storyboard scene;
- Add custom code to the new view-controller class.
We will perform each of these steps in the next sections.
Adding a New View-Controller Class to the Project
In the following steps, we are going to add a new class named WriteReviewViewController based on UIViewController to the project.
- Open the iAppsReview project in Xcode;
- In the Project Navigator on the left side of the Xcode window, click on the FeedbackViewController.m file. This causes the new class files you are going to create in the next steps to be listed in the Project Navigator directly below this file;
- Select File > New > File... from the Xcode menu. This displays the New File dialog (Figure 9);
Figure 9 - Select Cocoa Touch and Objective-C class in the New File dialog. |
- On the left side of the dialog, under the iOS section, select Cocoa Touch. In the panel on the right, select Objective-Cclass and then click Next. This displays the second step of the New File dialog (Figure 10);
Figure 10 - Create a WriteReviewViewController class based on UIViewController. |
- In the Subclass of box, enter UIViewController (if it's not already selected) and then, in the Class text field, add the prefix WriteReview to name the class WriteReviewViewController;
- Click the Next button to display the Save File dialog;
- Click the Create button to create the new view-controller class and save it in the project's root folder. After a few seconds, you will see two new files in the Project Navigator as shown in Figure 11;
Figure 11 - The new view-controller files in the Project Navigator |
- There is one other important change you need to make. Even though we made this new view controller a subclass of UIViewController, ultimately, because the Write Review scene contains a table view, we need to make it a subclass of UITableViewController instead (even though the table view contains a single, static cell). I didn't have you choose UITableViewController as the subclass in the New File dialog, because when you do this, Xcode adds a lot code to the view controller that is not necessary for a static table view.
So, to change the superclass of the new view controller, go to the Project Navigator and select the WriteReviewViewController.h file and change the superclass to UITableViewController as shown in Figure 12.
Figure 12 - Change the superclass to UITableViewController. |
That's it! Now you're read to associate the view controller with the Write Review scene.
Associating the WriteReviewViewController With the Write Review Scene
Now that you have created the new WriteReviewViewController class, it's time to associate it with the Write Review scene.
- In the Project Navigator, select the Mainstoryboard.storyboard file;
- Click on the status bar at the top of the Write Review scene to select the scene's view controller;
- Go to Xcode's Identity Inspector by clicking the third button from the left in the Inspector toolbar as shown in Figure 13. In the Class combo box, enter WriteReviewViewController. If after typing the first few characters, Xcode does not auto-fill the combo box with the class name, exit Xcode, relaunch Xcode, and then try it again.
Figure 13 - Set the view controller's class to WriteReviewViewController. |
Adding Custom Code to the View Controller
Adding custom code to the new view controller is usually the third step in the three key steps for adding custom code to a scene. In my previous post, Xcode generated a new action method for us when dragged from a connection well in the Connections Inspector down into the view-controller header file.
However, when you are adding code to a view controller that you think you may need in other apps (or even in other view controllers within the same app), you should consider putting it in a place where it can be accessed by multiple view controllers. This is definitely the case with the functionality that we are looking to add to the Write Review scene. Any scene that contains a text field or a text view will need the functionality to automatically hide the keyboard. This is where the UIViewController+mmExtensions class comes in. If you take a look at Figure 11, you can see I have added this new class to the project.
This class contains code that I find helpful in the apps that I create (feel free to use these in your own projects). Select the UIViewController+mmExtensions.h file in the Project Navigator and you will see the backgroundTouched: and textFieldReturn: methods shown in Figure 14.
Figure 14 - backgroundTouched: and textFieldReturn: methods of the mmViewController class |
This is a special kind of Objective-C class known as a category. A category is an extremely powerful tool that allows you to add methods to an existing class. In this case, the Cocoa Touch UIViewController class doesn't do everything we need it to (such as hide the keyboard when the user taps return on the keyboard or touches the background). We'll cover categories in more detail in a later post, but for now, just know that categories allow us to add the functionality that we need to the UIViewController class.
Notice the comments that describe how each method in the category is used. These are the kinds of comments you want to write for your own custom methods. They describe exactly how the method can be used. Also notice these methods are flagged as action methods (IBAction). That means we can easily connect these methods to user-interface control events.
So how can we use these methods in the WriteReviewViewController? Just follow the steps below!
- In the Project Navigator, select the WriteReviewViewController.h header file;
- Next, we need to import the category's header file. We'll explain import statements more thoroughly in a future post, but for now, all you need to know is that you need to import UIViewController+mmExtensions header file in order to reference its methods in the WriteReviewViewController class. To do this, click to the right of the existing #import statement, and then press return to add a new, empty line;
- Next, begin typing #import "UIViewController+mmExtensions". Before you finish typing, Xcode's Code Completion popup will appear and you will be able to select the import statement from the popup as shown in Figure 15.
Figure 15 - Code Completion appears for the #import command. |
Make sure you add the closing double quote as shown in Figure 16.
Figure 16 - The completed #import statement |
That's it! Now the WriteReviewController class inherits the backgroundTouched: and textFieldReturn: methods declared in the UIViewController+mmExtensions category;
- Before we connect these action methods to user-interface controls, let's take a look at the actual code that has been inherited. To do this, go to the Project Navigator and select the UIViewController+mmExtensions.m implementation file. At the bottom of the code file you should see the textFieldReturn: method shown in Figure 17.
Figure 17 - The textFieldReturn: method |
This method contains a single line of code, which is a message call! Check this code out for a minute and see if you can figure out what it does.
How did you do? I find a diagram can really help visualize what's going on, so I've added one in Figure 18. In the object-oriented programming world, this type of diagram is known as a sequence diagram because it shows the sequence of messages (I've modified the formal sequence diagram syntax slightly to make it easier to read).
Figure 18 - The textFieldReturn: sequence diagram |
As shown in Figure 18, when the user taps the return key in the keyboard, the textFieldReturn: action method is automatically executed. The text field object that currently has focus is passed to this method in the sender parameter. Then a resignFirstResponder message is sent to the text field object. This causes the text field to lose focus and the keyboard is automatically hidden;
- Directly above the textFieldReturn: method is the backgroundTouched: method shown in Figure 19.
Figure 19 - The backgroundTouched: method in the mmUIViewController class |
Again, this is a single line of code that is a message call. Take a moment to figure out for yourself what this method does.
Notice that rather than passing a message to the sender object, this code passes a message to self. Remember, self refers to the class that contains the code, which in this case, is the WriteReviewViewController class. Every view controller has a view property that references the view that is associated with the view controller. So, this code passes an endEditing: message to the WriteReviewViewController's view.
As shown in Figure 20, when the user taps the view background, the backgroundTouched: action method is automatically executed. From within this method, an endEditing: message is sent to the view which causes the keyboard to be dismissed.
Figure 20 - The backgroundTouched: sequence diagram |
That's it! Your view controller now possesses the action methods it needs.
Connecting User-Interface Controls to Action Methods
Now you're ready to connect user-interface controls to the view controller's action methods.
- In the Project Navigator, select the MainstoryBoard.storyboard file;
- In the Write Review scene, click on the App Name text field to select it;
- With the text field selected, go to the Connections Inspector by clicking the button on the far right in the Inspector toolbar (Figure 21);
- Next, click in the connection well to the right of the Did End On Exit event and drag down to the view controller icon located in the scene dock directly below the Write Review scene. The Did End On Exit event fires when the user taps the return key on the keyboard;
Figure 21 - Create a connection from the Did End on Exit event. |
- Let go of the mouse button to display the connection popup menu. Select the textFieldReturn: action method from the popup menu (Figure 22);
Figure 22 - Select textFieldReturn: from the popup menu. |
- Now you're ready to connect to the backgroundTouched: action method. iOS views do not have an event that automatically fires when the user touches the background of a view. So, to capture this action from the user, you need to add a gesture recognizer to the scene. The iOS gesture recognizer classes make it easy for you to capture and respond to a variety of gestures from your users. The Tap Gesture Recognizer recognizes single or double taps, as well as taps with multiple touches.
Drag a Tap Gesture Recognizer from the Object Library and drop it on the background of the Write Review scene as shown in Figure 23;
Figure 23 - Add a Tap Gesture Recognizer to the Write Review scene. |
- This displays a Tap Gesture Recognizer icon in the scene dock. Click on this icon (Figure 24) and then go to the Attributes Inspector (the third button from the right in the Inspector toolbar) and uncheck the Canceled in View option. This allows other controls in the view to receive taps;
Figure 24 - Uncheck the Canceled in View option. |
- With the gesture recognizer still selected, go to the Connections Inspector (the button on the far right in the Inspector toolbar). Under the Sent Actions section, click on the connection well to the right of the selector action and this time drag down to the view controller icon located on the left side of the scene dock as shown in Figure 25;
Figure 25 - Create a connection from the gesture recognizer's selector. |
- Let go of the mouse button to display the connection popup menu. Select the backgroundTouched: action method from the popup menu (Figure 26).
Figure 26 - Select backgroundTouched: |
Now the Write Review scene is ready to be tested!
Testing the Write Review Scene
Follow these steps to test the new "hide the keyboard" functionality.
- Click Xcode's Run button;
- When the app appears in the Simulator, click the Write a Review cell to display the Write Review scene;
- Click in the App Name text field and the keyboard should appear as shown in Figure 28;
Figure 28 - The keyboard appears when you click in the App Name text field. |
- Click the keyboard's return button, and the keyboard should be dismissed!
- Next, click in the text view (the large white user-interface control below the text field). This redisplays the keyboard;
- Clicking return at this point only adds a new, empty line in the text view (as it should). However, if you click on the background of the view, the keyboard should be dismissed.
Conclusion
We covered a lot of conceptual ground in this post. Once you have mastered messaging in Objective-C, it goes a long way toward your goal of becoming an app developer. As usual, I recommend you read through this post again until terms such as instance method, class method, receiver, selector, argument, message, and return value become more familiar. In my upcoming posts, we will be able to move the app forward more quickly now that you understand the important concept of passing messages.