By Kevin McNeish on Thu, 05/28/2015
Do you have an idea for an app but lack the programming knowledge to begin building it? In this weekly blog series, 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 17 of the series. If you are just getting started now, check out the beginning of the series here. (This post has been updated to Swift 1.2, iOS 8 and Xcode 6.3.)
In my previous post, you learned how to generate Swift classes from entities in a data model and you were introduced to the mmBusinessObject class, which provides an easy-to-use wrapper for Core Data classes. In this week's post, we're going to create our app's custom business controllers and take them for a test drive!
To perform the steps outlined in this post, you can get the latest version of the iAppsReview project at this link. I recommend following the steps in this post yourself, but if you get stuck, you can get the finished app at this link.
Creating Business Controllers
Figure 1 shows the three business controllers we need to create for the app, and all three will be subclasses of the ABusinessObject class.
|Figure 1 - The business controller classes are subclasses of ABusinessObject.|
Creating the Review Business Controller
First, let's create a Review business controller object.
- Open the iAppsReview project in Xcode.
- In the Project Navigator, right click the AppCategoryEntity.swift file (so the new file is added directly below AppCategoryEntity.swift), and select New File... from the popup menu.
- On the left side of the New File dialog under the iOS section, select Source. On the right side of the dialog, select the Swift File template, and then click the Next button (Figure 2).
|Figure 2 - Create a new Swift class.|
- Click the Next button to launch the Save File dialog. In the Save As box, change the name of the file to Review.swift. Click the Create button, which adds the new Review class file to the Project Navigator as shown in Figure 3.
|Figure 3 - The newly added Review class file|
- Now let's add a class declaration to the code file. In the code file below the import Foundation statement, type the word class. This brings up the Code Completion window (Figure 4). Select class - Swift Subclass and press return.
|Figure 4 - Declare a new class|
In the name placeholder, enter Review<T:ReviewEntity>. Press tab and enter ABusinessObject<T> in the super class placeholder. When you're finished your code should look like Figure 5.
|Figure 5 - Declaring a Swift subclass|
- We don't need any methods just yet, so tab to the properties and methods placeholder and press the delete key.
This code uses Swift's generics feature to associate the ReviewEntity class with the Review business controller. This allows you to avoid typing the entity class name every time you want to create, retrieve, update, or delete a ReviewEntity. For more information on how this works, check out my blog post on generics at this link.
Creating the AppCategory Business Controller
Now let's create an AppCategory business controller. The instructions are very similar to those in the previous section, so I'll abbreviate them a bit.
- Right-click the iAppsReview.xcdatamodeld file in the Project Navigator (so the new file is added directly below it), and select New File... from the popup menu.
- On the left side of the New File dialog under the iOS section, select Source. On the right side of the dialog, select the Swift File template.
- Click the Next button to launch the Save File dialog. In the Save As box, change the name of the file to AppCategory.swift. Click the Create button to add the new AppCategory class file to the Project Navigator as shown in Figure 6.
|Figure 6 - The new AppCategory class file|
- Change the name and super class placeholders and delete the properties and methods placeholder as shown in Figure 7.
|Figure 7 - Declare the AppCategory class.|
Again, this specifies the name of the entity class associated with the business controller.
Creating the User Business Controller
Now let's create our final class, the User business controller.
- Right-click the ReviewEntity.swift file in the Project Navigator (so the new file is added directly below it), and select New File... from the popup menu.
- On the left side of the New File dialog under the iOS section, select Source. On the right side of the dialog, select the Swift File template.
- Click the Next button to launch the Save File dialog. In the Save As box, change the name of the class to User.swift. Click the Create button to add the new User class file to the Project Navigator as shown in Figure 8.
|Figure 8 - The new User class file|
- Change the name and super class placeholders and delete the properties and methods placeholder as shown in Figure 9.
|Figure 9 - Declare the User class.|
This specifies that UserEntity is the name of the entity class associated with the business controller.
Using Business Controllers with View Controllers
When you place all of your entity manipulation code in business controllers, you create an app architecture that is easier to conceive, create, and maintain. In order to use the code within these business controllers, you need to instantiate them from within your app's view controllers and call methods on them that create, retrieve, update, and delete entities.
Figure 10 shows the collaboration between view controllers and business controllers.
|Figure 10 - View controllers can call on the services of business controllers to manipulate entities.|
The grouping of view controllers and business controllers you see in this figure is actually what you are going to set up in this and upcoming posts. Although the diagram only shows one business controller referenced from each view controller, a single view controller can work with multiple business controllers.
Setting Up the App Category Scene
As promised earlier in this blog series, we are going to take the iAppsReview prototype app and turn it into a real app. We'll start with the App Category scene since it's an easy one.
Currently, the App Category scene contains a hard-coded list of categories that you added when you first created the project (Figure 11).
|Figure 11 - The App Category scene|
Rather than having a hard-coded list of categories, we want to change this scene so the categories are populated from a list of CategoryEntity objects stored in the database and dynamically retrieved at run time. This allows us to add new categories to the list in the future without changing the app. Let's get started!
- In the Project Navigator, select the Main.Storyboard file and scroll the storyboard so you can see the App Category scene.
- As shown in Figure 11, this scene has a table view that contains nine prototype cells that all have the same formatting. We only need one cell that will be used as a prototype for all cells in this table, so let's delete the last eight cells in the table view.
To do this, click the second cell in the table view to select it, hold down the shift key and click on the third through ninth cells to select them too;
- With these cells selected, press the delete key to delete the cells and leave the first cell remaining as shown in Figure 12.
|Figure 12 - Delete all but the first App Category cell.|
- In the App Category scene, click in the gray area below the table view. Go to the Attributes Inspector (third button from the right in the Inspector toolbar) and change the Content attribute from Static Cells to Dynamic Prototypes. Doing this adds a Prototype Cells header label above the table view (Figure 13).
|Figure 13 - Set the table view's Content to Dynamic Prototypes.|
Header labels are used to describe the contents of a table view, but since the navigation bar already contains the text App Category, there's no need to use the header label. You can simply ignore the header label and it won't appear at run time.
- Click on the Entertainment table view cell to select it, and then go to the Attributes Inspector and set the cell's Identifier to CategoryCell (Figure 14).
|Figure 14 - Set the cell's Identifier to CategoryCell.|
This identifier allows you to reference this specific cell from code within your view controller, which we will create next.
Creating an AppCategoryViewController
Now we need to create a table view controller for the App Category scene. This table view controller will create an instance of the AppCategory business controller and fill the table view with AppCategoryEntity objects.
- Right-click the iAppsReview group folder in the Project Navigator, and select New File... from the shortcut menu.
- On the left side of the New File dialog under the iOS section, select Source. On the right side of the dialog, select the Cocoa Touch Class template, and then click Next.
- In the next step of the dialog, set the Subclass Of to UITableViewController, then set Class to AppCategoryViewController (Figure 15).
|Figure 15 - Create AppCategoryViewController as a subclass of UITableViewController.|
- Click the Next button to display the Save File dialog, and then click Create to add the new AppCategoryViewController class file to the project.
- Whenever you create a new view controller for a particular scene, it's a good idea to immediately go to that scene and associate it with the scene.
To do this, go to the Project Navigator, select the Main.storyboard file and then click the status bar at the top of the App Category scene to select the table view controller. You will know you have selected it properly when a blue highlight appears around the scene as shown in Figure 16. Next, go to the Identity Inspector (third button from the left in the Inspector toolbar) and change the class to the new AppCategoryViewController.
|Figure 16 - Set the App Category view controller's Class to AppCategoryViewController.|
- Let's go back and set up the AppCategoryViewController class. Select AppCategoryViewController.swift in the Project Navigator, and add the property declarations shown in Figure 17 below the class declaration (don't forget to add the curly braces).
|Figure 17 - Add properties to the class.|
The appCategory property holds a reference to the AppCategory business controller object, and the appCategoryList array property will be used to hold the AppCategoryEntity objects returned from the business controller.
- In the view controller's viewDidLoad method, delete all of the existing comment lines (the lines in green) and add the code shown in Figure 18 in its place.
|Figure 18 - Add code that retrieves a list of AppCategoryEntity objects|
This code calls the getAllEntities method on the appCategory business controller, storing the resulting entities into the appCategoryList array. As its name suggests, this method returns all entities of a particular type. The AppCategory class (as well as all of your other business controller classes) inherits the getAllEntities method from the mmBusinessObject class. Rather than having to type several lines of code (as you would have to do with out-of-the-box Core Data), you only need one line of code to retrieve the CategoryEntity objects. This is the beauty of object-oriented inheritance and encapsulation!
- Now it's time to change the methods of the table view controller that are used to fill the associated table view in the App Category scene. In a future post I'll discuss table view controllers in greater detail, but for now I'll just give you the information you need to know to understand the basics.
Scroll down to the numberOfSectionsInTableView: method. This method is used to specify the number of sections in the table view. Delete the line that begins with #warning. Since this table view only has one section, change the method to return 1 as shown in Figure 19.
|Figure 19 - The numberOfSectionsInTableView: method specifies the number of sections in the table view.|
- Scroll down to the numberOfRowsInSection: method. This method specifies the number of rows in a particular section of the table view. Delete the #warning line and change the return statement to the code shown in Figure 20.
|Figure 20 - The tableView:numberOfRowsInSection: method specifies the number of rows in a section of the table view.|
Since there is only one section in this table view, we don't have to check the section number that is passed to this method. The code you have added returns the number of AppCategoryEntity objects in the appCategoryList array. This causes the table view to create one row for each entity object in the array.
- Now scroll down to the tableView:cellForRowIndexPath: method. Uncomment this method by deleting the /* comment characters above it and the */ comment characters below it. Change the code in this method to the code shown in Figure 21.
|Figure 21 - tableView:cellForRowAtIndexPath configures the rows in the table view|
This method gets called once for every AppCategoryEntity in the appCategoryList array. The first line of code calls a method on the table view asking it for a cell with the CategoryCell identifier. This is the identifier you specified for the remaining cell in the App Category scene earlier in this post. The table view returns the prototype cell with that identifier.
Next, this code gets the AppCategoryEntity in the appCategoryList with the specified row number. In Swift, collections are numbered starting with zero. So, a collection with 10 items would be numbered 0 through 9. The first time this method is called, a zero value is passed in as the row number. That zero value is then used to reference the first item in the appCategoryList and the first AppCategoryEntity object in that array is returned. The next time the method is called, a 1 is passed in and the second AppCategoryEntity in the list is returned, and so on.
After an entity is retrieved, its name value is stored in the cell's main text label, and the cell is returned from the method.
- Now that the setup of the App Category scene is complete, it's time to run the App to see what it looks like at run time. To do this, click the Run button in Xcode. When the app appears in the Simulator, select Write a Review and then in the Write Review scene, click the App Category row and you will see the App Category scene shown in Figure 25.
|Figure 25 - The App Category scene is empty!|
You may be surprised to see that there aren't any rows in the table view! That's because we never created a database and added any records to it.
When your app first tries to access a database, if it doesn't exist, Core Data automatically creates an empty database for you. In my next post, we'll take a close look at this database, and then we will add CategoryEntity objects to it and see how they fill the list at run time!