How To Design An App : Real Estate App Sample – Part 1

By
On March 14, 2013

In this two-part tutorial, I will show you how to design an app that looks appealing. As an example, the app will be a real estate property search for iOS using the Zoopla Property API.

The final app will look like the image below. It makes use of the Estate design template from App Design Vault.

figure-0

In the first part, we will lay the foundation of the application by querying the Zoopla API for properties based on a city or postal code. The second part of this tutorial zooms in on the user interface and user experience. We will make use of the brand new Real Estate template of App Design Vault to give the application a unique and professional look. Let’s get started.

Zoopla

There are several web services that we can use for our application. I have chosen for an API provided by Zoopla, a leading provider of property data in the United Kingdom with information on more than 27 million homes. The API has a flexible REST interface and will provide us with data for our application. To follow along, you need an API key, which you can obtain by registering for a free user account. The process is straightforward and completely automated. It takes no more than five minutes from start to finish.

Getting Started

Project Setup

Create a new Xcode project based on the Single View Application template (figure 1) and give it a name of Real Estate (figure 2). Make sure to enable ARC and storyboards for the project (figure 2).

How To Design An App

How To Design An App

AFNetworking and SVProgressHUD

AFNetworking is by far my favorite networking library so that is the library we will be using to query the Zoopla API. Download the latest version from GitHub and add the library to your project. Because some elements of AFNetworking depend on the System Configuration and Mobile Core Services frameworks, it is necessary to link the project against both frameworks.

Another great library is SVProgressHUD. Download the latest version from GitHub and add the SVProgressHUD class to your project. SVProgressHUD relies on the Quartz Core framework so make sure to also link your project against the Quartz Core framework.

CocoaPods makes managing third-party libraries trivial so feel free to use CocoaPods to add AFNetworking and SVProgressHUD. Before we move on, add four import statements to the project’s precompiled header file (Real Estate-Prefix.pch). Add an import statement for the System Configuration and Mobile Core Services frameworks, and do the same for the AFNetworking and SVProgressHUD libraries. This will make AFNetworking and SVProgressHUD available throughout the project.

#import 

#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif

#ifdef __OBJC__
    #import 
    #import 
    #import 
    #import 

    #import "AFNetworking.h"
    #import "SVProgressHUD.h"
#endif

HTTP Client

The AFHTTPClient class makes consuming web services easy. To really benefit from the AFHTTPClient class, it is recommended to create a custom subclass for each web service. That is what we will do first.

Create a new class, name it ADVZooplaClient, and make it a subclass of AFHTTPClient (figure 3). The implementation of the ADVZooplaClient class isn’s complicated as you can see below. In the class’s header file, we declare a single class method that gives access to the class’s singleton object. There is no need to instantiate multiple instances of the API client.

How To Design An App

#import "AFHTTPClient.h"

@interface ADVZooplaClient : AFHTTPClient

#pragma mark -
#pragma mark Shared Instance
+ (ADVZooplaClient *)sharedClient;

@end

In ADVZooplaClient.m, we implement the sharedClient method. The singleton object is instantiated using initWithBaseURL:, the designated initializer of the AFHTTPClient. By passing and storing the base URL of the Zoopla API (https://api.zoopla.co.uk/api/v1/) as part of the HTTP client, it is easy to interface with the Zoopla API.

We also override initWithBaseURL: as shown below. Because we will be requesting a JSON response from the Zoopla API, we register the AFJSONRequestOperation class as the AFHTTPRequestOperation subclass to use for requests initiated by our API client. It is also important to set the Accept header of all the requests to application/json. Even though the Zoopla API returns an XML response by default, I prefer working with JSON, which is also supported by the Zoopla API.

#import "ADVZooplaClient.h"

@implementation ADVZooplaClient

static ADVZooplaClient *_sharedClient = nil;

#pragma mark -
#pragma mark Shared Instance
+ (ADVZooplaClient *)sharedClient {
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedClient = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"https://api.zoopla.co.uk/api/v1/"]];
    });

    return _sharedClient;
}

#pragma mark -
#pragma mark Private Methods
- (id)initWithBaseURL:(NSURL *)url {
    self = [super initWithBaseURL:url];

    if (self) {
        // Register HTTP Operation Class
        [self registerHTTPOperationClass:[AFJSONRequestOperation class]];

        // Accept HTTP Header
        [self setDefaultHeader:@"Accept" value:@"application/json"];
    }

    return self;
}

@end

Creating the Storyboard

The flow of the application is straightforward, the user enters a city name or postal code in a text field, sets a radius (in miles) for the search query, and queries the Zoopla API by tapping a button. If the API returns a valid response, we show the user a summary of the results in a table view. To view the specifics of a particular property, the user taps an item in the list of results. Easy. Right?

Renaming ADVViewController

This application flow translates into a simple storyboard layout. First, however, I would like to rename the ADVViewController class to ADVSearchViewController to avoid confusion in the rest of the discussion. Open ADVViewController.h, highlight the class name, right-click, and select Refactor > Rename… from the menu. Rename the class to ADVSearchViewController. Xcode takes care of the rest.

Creating Classes

Before we create the storyboard layout, we need to create the view controller that displays the list of results as well as the view controller that displays the details of a property. Name the view controllers ADVPropertiesViewController and ADVPropertyDetailsViewController respectively.

Creating the Storyboard

Open the main storyboard (MainStoryboard.storyboard) and select the search view controller in the storyboard. With the search view controller selected, open the Editor menu, select Embed In, and choose Navigation Controller (figure 4).

How To Design An App

Drag a table view controller from the Object Library and position it to the right of the search view controller. Select the table view controller, open the Identity Inspector and set its class to ADVPropertiesViewController. Control and drag from the search view controller to the properties view controller and select Push from the pop-up menu. Select the segue from the search view controller to the properties view controller, open the Attributes Inspector, and give the segue an identifier of PropertiesSegue (figure 5).

How To Design An App

Drag another view controller from the Object Library and position it to the right of the properties view controller. Select the new view controller and change its class to ADVPropertyDetailsViewController in the Identity Inspector. Control drag from the properties view controller to the property details view controller and select Push from the pop-up menu. Select the segue from the properties view controller to the property details view controller and set its identifier to PropertyDetailsSegue.

How To Design An App

A Simple Search Form

Mobile applications should be easy to use. The form of the search view controller will contain one text field, a slider, and a button. How is that for ease of use? Open the header file of the ADVSearchViewController class and create an outlet for the text field (areaTextField) and an outlet for the slider (radiusSlider) with which the user can set the radius of the search query. Create an action named search: for the button.

#import 

@interface ADVSearchViewController : UIViewController

@property (weak, nonatomic) IBOutlet UITextField *areaTextField;
@property (weak, nonatomic) IBOutlet UISlider *radiusSlider;

- (IBAction)search:(id)sender;

@end

Jump back to the storyboard and add a text field, a slider, and a button to the search view controller’s view. Connect the text field and the slider with the outlets we created a moment ago. Connect the search: action with the button and give the button a title of Search (figure 7). Set the minimum value of the slider to 0.5 (miles), the maximum value to 40 (miles), and the current value to 2 (miles). Don’t worry too much about the form’s appearance. We will style the form in the second part of this tutorial.

How To Design An App

It is time to implement the search: action we declared earlier. Start by importing the header file of the ADVZooplaClient and add a private property of type NSArray named properties to store the properties that we get back from the Zoopla API.

#import "ADVSearchViewController.h"

#import "ADVZooplaClient.h"

@interface ADVSearchViewController ()

@property (strong, nonatomic) NSArray *properties;

@end

The search: action is not that complicated thanks to the ADVZooplaClient class we created earlier. The first thing we do after the user taps the search button is hide the keyboard and show an activity indicator to inform the user that the search query is in progress. The next step involves creating a dictionary containing the request parameters. The dictionary includes the required API key, the page size or the number of results returned, the area of the search query (city or postal code), and the radius of the search query (in miles). Keep in mind that the Zoopla API is limited to the United Kingdom so make sure to test your application by entering a city or postal code in the United Kingdom.

As I mentioned earlier, the AFHTTPClient class makes consuming web services painless. The API endpoint that we use for this query is property_listings. By appending the .js suffix, we inform the Zoopla API that we request a JSON response. In the success block, we hide the activity indicator and store the list of properties in the properties property we created earlier. To test the search: action, we log the properties property to the Xcode Console. Build and run the application to see if everything works as expected.

- (IBAction)search:(id)sender {
    // Hide Keyboard
    [self.areaTextField resignFirstResponder];

    // Show Progress HUD
    [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];

    // Request Parameters
    NSDictionary *parameters = @{
                                 @"api_key" : @"xxxxxxxxxxxxxxxxxxxxxxxx",
                                 @"page_size" : @50,
                                 @"area" : self.areaTextField.text,
                                 @"radius" : [NSNumber numberWithFloat:self.radiusSlider.value]
                                 };

    // Send Search Query to Zoopla API
    [[ADVZooplaClient sharedClient] getPath:@"property_listings.js" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
        // Hide Progress HUD
        [SVProgressHUD dismiss];

        if ([operation isKindOfClass:[AFJSONRequestOperation class]]) {
            if ([responseObject objectForKey:@"listing"]) {
                self.properties = [responseObject objectForKey:@"listing"];
                NSLog(@"Properties > %@", self.properties);
            }
        }

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        // Hide Progress HUD
        [SVProgressHUD dismiss];

        NSLog(@"Error %@ with User Info %@.", error, [error userInfo]);
    }];
}

Listing Results

To list the properties in the table view of the properties view controller, we need to head back to the main storyboard. Select the prototype cell in the table view of the properties view controller and set the cell’s type to Subtitle and its identifier to PropertyCellIdentifier.

#import 

@interface ADVPropertiesViewController : UITableViewController

@property (strong, nonatomic) NSArray *properties;

@end

The next step is to add a public property of type NSArray named properties to the header file of the ADVPropertiesViewController class. The rest of the implementation of the ADVPropertiesViewController class is pretty basic. Declare the property cell identifier that we specified in the main storyboard in ADVPropertiesViewController.m as shown below.

static NSString *PropertyCellIdentifier = @"PropertyCellIdentifier";

To finalize the implementation of the ADVPropertiesViewController class, we need to implement the table view data source protocol as shown below. If you have worked with table views before, there shouldn’t be any surprises here. Because the Zoopla API occasionally returns empty data fields, I have added some checks before populating the cell’s text and detail text labels to prevent any bogus data from being displayed in the table view.

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.properties ? 1 : 0;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.properties count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PropertyCellIdentifier];

    // Fetch Listing
    NSDictionary *property = [self.properties objectAtIndex:[indexPath row]];

    // Helpers
    NSString *town = [property objectForKey:@"post_town"];
    NSString *address = [property objectForKey:@"displayable_address"];

    // Configure Cell
    if (town && [town isKindOfClass:[NSString class]]) {
        [cell.textLabel setText:town];
    } else {
        [cell.textLabel setText:@"Location Unknown"];
    }

    if (address && [address isKindOfClass:[NSString class]]) {
        [cell.detailTextLabel setText:address];
    } else {
        [cell.detailTextLabel setText:@"Address Unknown"];
    }

    return cell;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return NO;
}

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    return NO;
}

All that is left for us to do, is pushing the properties view controller onto the navigation stack when the application receives a list of properties from the Zoopla API. We do this in the search: action as shown below.

- (IBAction)search:(id)sender {
    // Hide Keyboard
    [self.areaTextField resignFirstResponder];

    // Show Progress HUD
    [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];

    // Request Parameters
    NSDictionary *parameters = @{
                                 @"api_key" : @"xxxxxxxxxxxxxxxxxxxxxxxx",
                                 @"page_size" : @50,
                                 @"area" : self.areaTextField.text,
                                 @"radius" : [NSNumber numberWithFloat:self.radiusSlider.value]
                                 };

    // Send Search Query to Zoopla API
    [[ADVZooplaClient sharedClient] getPath:@"property_listings.js" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
        // Hide Progress HUD
        [SVProgressHUD dismiss];

        if ([operation isKindOfClass:[AFJSONRequestOperation class]]) {
            if ([responseObject objectForKey:@"listing"]) {
                self.properties = [responseObject objectForKey:@"listing"];
                [self performSegueWithIdentifier:@"PropertiesSegue" sender:self];
            }
        }

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        // Hide Progress HUD
        [SVProgressHUD dismiss];

        NSLog(@"Error %@ with User Info %@.", error, [error userInfo]);
    }];
}

There is one caveat, though. We need to set the properties property of the properties view controller with the list of properties we received from the Zoopla API. We do this in the prepareForSegue:sender: method of the search view controller as shown below. Don’t forget to import the header file of the ADVPropertiesViewController class.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"PropertiesSegue"]) {
        ADVPropertiesViewController *vc = [segue destinationViewController];
        [vc setProperties:self.properties];
    }
}
#import "ADVSearchViewController.h"

#import "ADVZooplaClient.h"
#import "ADVPropertiesViewController.h"

Build and Run

Build and run the application to see everything in action. There are still a number of rough edges that we need to polish up, but we now have a foundation that we can build on.

How To Design An App

Wrapping Up

You can download the sample project here.

As you can see, the Zoopla API is easy to use and it doesn’t take long to have a prototype of the application up and running. In the second part of this tutorial, we will make everything pretty with the brand new Real Estate template of App Design Vault and we will also implement the property details view controller.