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 much fun turning your ideas into reality can be! This is Part 12 of the series. If you're just getting started now, check out the beginning of the series here.
One of the best software development books of all time is Steve McConnell's Code Complete. Whether you are a seasoned software developer or a brand new programmer, regardless of the platform or language in which you write code, I highly recommend checking out this book. It will change your way of thinking and vastly improve the quality of the code you write.
'Software Accretion'—Building Over Time
After reading Code Complete years ago, the book's comparison of software development to oyster farming really stuck with me. McConnell used the term software accretion to describe the process of building software over a period of time. The word "accretion" refers to any growth or increase in size by a gradual external addition or accumulation. This is the way an oyster makes a pearl; by gradually adding small amounts of calcium carbonate over a period of time, a pearl grows larger and larger.
With incremental software development, you start out by making the simplest version of a system that will run. You create a skeleton strong enough to hold the real system as it's developed, just like an oyster that begins building a pearl with a small grain of sand. This is exactly what we have done so far in this column with the iAppsReview app. We built a prototype of the app first, and gradually, over time, we have added code each week with the final goal of creating a fully-functioning app.
Hardening Your Code
As part of the incremental process of building an app, you need to take a look at your code and ask the question, "What could go wrong?" Typically, one of the biggest variables to consider is your users. They will constantly surprise you by using your app in ways you didn't even consider. I've worked with quite a few development teams over the years, and I have yet to see a case where developers weren't astonished by watching people use their software. When it comes to app development, it is critical that you let others kick the tires on your app before submitting it to the App Store. Their feedback will absolutely improve the quality of your app's user experience.
Let's take a look at iAppsReview, identify areas where problems may occur, and then harden our code to avoid any issues. You can get the project we have completed so far at this link.
As it stands right now, if the user doesn't enter an app name or comments in the Write Review scene, the app doesn't crash; but when they try to share the review on Twitter, they will get an empty tweet except for the hyphen as shown in Figure 1.
|Figure 1 - The user can send an empty tweet.|
So how should we address this problem? It's a best practice to look at the built-in iOS apps to see how Apple handles a particular situation, and use that as a guide for our own apps. For example, when specifying a Twitter account in the Settings app, the Sign In button is disabled until the user enters both a User Name and Password (Figure 2).
|Figure 2 - The Sign In button is disabled until the user enters a User Name and Password.|
This also is a good approach for the Write Review scene. Ultimately, we only want to enable the Share button if there is text in both the App Name text field and comments text view. This means each time the user types a character, we need to check both user-interface controls. If either is empty, the Share button must be disabled. If both controls contain text, the Share button can be enabled. We have to perform this check for every character the user types, because they could press the delete key, leaving one of the user-interface controls empty.
I recommend trying the step-by-step instructions in the following sections on your own, but if you run into trouble, you can watch me perform these steps for you at this link.
Creating a Share Button Outlet
Since we need to access the Share button so we can enable and disable it, our first step is to create an outlet for the button. To do this, follow the steps listed below.
- Open the iAppsReview project in Xcode;
- In the Project Navigator, select the MainStoryboard.storyboard file;
- In the Write Review scene, click on the Share button in the top-right corner of the scene;
- Go to the Attributes Inspector (the third button from the right in the Inspector toolbar), and uncheck the Enabled check box as shown in Figure 3. This causes the Share button to look disabled at design time and when the scene first appears at run time;
|Figure 3 - Uncheck the Enabled check box.|
- Next, display the Assistant Editor by clicking the center button in the Editor button group at the top of the Xcode window. This should display the WriteReviewViewController.h file in the Assistant Editor;
- Hold the control key down, click on the Share button, and drag down into the WriteReviewViewController.h file as shown in Figure 4;
|Figure 4 - Create an outlet for the Share button.|
- When you see the Insert Outlet, Action, or Outlet Collection popup, let go of the mouse button and the control key. This displays the Insert Outlet popup. Enter btnShare as the outlet Name and then click the Connect button (Figure 5). This adds a new btnShare outlet property to the header file.
|Figure 5 - Create an outlet named btnShare.|
Configuring the App Name Text Field
Now let's configure the App Name text field to enable and disable the Share button.
- Click on the App Name text field to select it in the design surface and then go to the Connections Inspector (the button on the far right in the Inspectors toolbar);
- Under the Sent Events section, click the connection well to the right of the Editing Changed event and drag down into the WriteReviewViewController.h file as shown in Figure 6. The Editing Changed event fires each time the user enters or deletes a character in the text field;
|Figure 6 - Create an action method for the Editing Changed event.|
- When the Insert Action popup appears, let go of your mouse button and the control key. This displays the Create Action Method popup (Figure 7). Enter appNameChanged as the method Name and then click the Connect button. This adds a new action method to the WriteReviewViewController.h file. You can close the Assistant Editor now by clicking the left button in the Editor button group;
|Figure 7 - Create an action method named appNameChanged.|
- Now let's implement the new method. To do this, go to the Project Navigator and click on the WriteReviewViewController.m file to display it in the Code Editor. Enter the code shown in Figure 8. If you need help, I recommend watching the video I have created for this post.
|Figure 8 - The code in this method enables and disables the Share button.|
This is the first time I have shown this type of code in my blog post so I'll explain how it works. This is an Objective-C if else statement. It belongs to a family of conditional statements and it allows you to execute one set of code or another based on a condition.
The condition that is checked by this statement is contained within parentheses immediately following the if as shown in the first line of code in this method. This particular condition contains a compound comparison, where two values are checked. The double vertical lines between the two conditions ( || ) is a logical OR operator. This means if the first condition OR the second condition evaluates to YES, then the code within the curly braces directly following the if is executed. Otherwise, the code contained in the curly braces following the else statement is executed.
First, a test is performed to see if the length of the text in the tvwReview control is equal to zero, which it will be if the text field is blank. If this part of the condition is true, then the code that disables the button is executed without checking the second part of the condition. There's no need to check because if either part of the condition is true, the button should be disabled. If the first part of the condition is true, then the second part of the condition is checked. If the length of the text property in the text field is equal to zero, then the code that disables the button is executed.
If both parts of the condition are false, then the code in the else statement executes, which enables the Share button;
- Let's give the code a try. Click Xcode's Run button, and when the app appears in the Simulator, select the Write a Review option. Notice the Share button in the Write Review scene looks disabled;
- Type a few characters in the text view (the large white box) first. Afterwards, click in the App Name text field, and as soon as you type the first character, the Share button should be automatically enabled. If you subsequently delete the character in the text view, the Share button should be disabled again.
Configuring the Review Comments Text View
Now you're ready to set up the review comments text view. We have to take a different approach with the text view because it doesn't have an Editing Changed event as the text field does (you can click on the text view in the design surface and then go to the Connections Inspector to see what I mean).
As is the case with the text view, if you don't find the event that you need with a particular user-interface control, your next step is to check if the control has a delegate protocol that can be adopted so that you can be notified of important events (see my previous post for a discussion of delegates and protocols). If you look at the UITextView documentation, you will find there is indeed a delegate property whose type is a protocol named UITextViewDelegate. This protocol contains a textViewDidChange: method (Figure 9), which is exactly what we need. As the documentation states, this method is automatically called on the delegate when the user changes the text in the text view.
|Figure 9 - The textViewDidChange: method is called when the user changes the text in the text view.|
Let's adopt this protocol now.
- In the Project Navigator, select the WriteReviewViewController.h header file;
- Add the code shown in Figure 10 to adopt the UITextViewDelegate protocol, and remember to add a comma after the UINavigationControllerDelegate protocol at the end of the previous line of code;
|Figure 10 - Adopting the UITextViewDelegate protocol|
- Now let's implement the protocol. To do this, click the WriteReviewViewController.m implementation file in the Project Navigator and add the new, empty textViewDidChange: shown in Figure 11 directly below the appNameChanged: method.
|Figure 11 - Add the textViewDidChange: method.|
Line for line, we need the code in the textViewDidChange: method to do exactly what the code in in the appNameChanged: method is doing. So what should you do? First of all, let's talk about what you should not do.
One of the biggest mistakes rookie developers (and unfortunately even some seasoned developers) make is copying the code from one method and pasting it into another. Why is this a problem? One of your goals as a developer is to avoid creating duplicate code. Why? If you ever have to make a change to the code (and eventually you will) it means there is more than one place where you have to make the change.
So what should you do instead? You should break the code out into a separate method that can be called from multiple places in your app. That's exactly what we're going to do now;
- Add a new, empty isReadyToShare method as shown in Figure 12 directly below the textViewDidChange: method. When we finish adding the code, this method will return YES if the Share button should be enabled, and NO if it should not;
|Figure 12 - Add the new isReadyToShare method.|
- Now, instead of doing a copy and paste, we are going to cut and paste the code from the textViewDidChange: method into the new isReadyToShare method. To do this, select all of the code in the textViewDidChange: method as shown in Figure 13 by clicking and dragging from the first line of code to the last line of code in the method;
|Figure 13 - Select all code in the appNameChanged: method.|
- Next, type Command+X to cut the code from this method;
- Now click inside the curly braces of the isReadyToShare method and press Command+V to paste the code into the method. When you're finished, these three methods should look like Figure 14;
|Figure 14 - The code has been cut from appNameChanged: and pasted into isReadyToShare.|
- Now we need to change the code in this method to return a NO if the Share button should not be enabled, and YES if it should. To do this, replace the code between curly braces in the if else statement as shown in Figure 15;
|Figure 15 - isReadyToShare returns NO to disable the Share button and YES to enable it.|
- Now add the code shown in Figure 16 to the appNameChanged: and textViewDidChange: methods. This code passes an isReadyToShare message to the view controller and stores the returned value into the enabled property of the Share button.
|Figure 16 - Pass an isReadyToShare message from both methods.|
- There's one more step we need to take to make this work properly. We need to store a reference to the WriteReviewController in the delegate property of the text view.
To do this, go to the Project Navigator and select the MainStoryboard.Storyboard file and then go to the Connection Inspector (the button on the far right in the Inspectors toolbar). Click the connection well to the right of the delegate outlet and drag down to the Write Review View Controller icon in the dock below the Write Review scene as shown in Figure 17. When you release your mouse, the delegate outlet and view controller will be connected.
|Figure 17 - Connect the text view's delegate property to the WriteReviewViewController.|
Kicking the Tires!
Now we're ready to kick the tires and see how our changes work.
- Click the Run button in Xcode and when the app appears in the Simulator, select the Write a Review option;
- Type text into the App Name text field first, and then type in the text view afterwards. Notice as soon as you type the first character into the text view, the Share button is disabled!
- Try deleting all the characters in one of the controls and then the other to see the Share button get enabled and disabled.
Growing the Pearl
If you were building this app for a client, you may show them the app to get some feedback after adding this new functionality. At this point, what if the sponsor tells you a zero star rating is not acceptable (just as in the App Store)? Now you need to change the app to ensure the Share button is not enabled until a rating is selected.
I'd like you to think about what you would have to do if you had simply copied the code that checked for an empty text field and text view from the appNameChanged: method and pasted it into the textViewDidChange: method. Now you would have two places where you would have to add code that checks if the user selected a rating for the app! This is not the kind of app you want to create. It is far better to do what we have done in this post and create a separate method that can be called from the appNameChanged: and textViewDidChange: methods, because there is only one place where we have to change the code.
Your Homework Assignment
For your homework assignment this week, I'd like you to enhance the app so the user can only share their review if they have selected a rating. Doing this involves the following key steps:
- Create an outlet for the starRating control (you will need to import the mmStarRating.h header file);
- Change the WriteReviewViewController to adopt the StarRatingDelegate protocol;
- Add the starRating:ratingDidChange: delegate method to the WriteReviewViewController class;
- Add code to isReadyToShare: to check the starRating control's rating property to see if the user has selected a rating;
- Add code to the starRating:ratingDidChange: delegate method to set the enabled property of the Share button;
- Note that you can't set the delegate property in the Storyboard as you did with the text view control. You need to add code to WriteReviewViewController's viewDidLoad method to store a reference to the view controller in the delegate property;
When you have tried all these steps yourself, check out the video at this link where you can watch me add this functionality to the app.
Creating high quality apps is both a science and an art. The effort you put into creating a well-designed app will pay itself back in dividends many times during the life of your app. I recommend you read through books such as Code Complete to learn even more great coding practices and elevate your app development skills!