Objectively Speaking: A Crash Course in Objective-C for iOS 6

Note from Ray: This tutorial is now fully up-to-date for iOS 6, and uses Modern-Objective-C syntax. Here’s the pre iOS 6 version if you need it! This is a post by iOS Tutorial Team Member Linda Burke, an indie iOS developer and the founder of canApps. Are you a software developer skilled in another platform, […] By .

Leave a rating/review
Save for later
Share
You are currently viewing page 4 of 5 of this article. Click here to view the first page.

Options, Options, Options

First you need to go back to your class header file, ViewController.h, and add a new property.

@property (nonatomic, strong) IBOutlet UISegmentedControl *quoteOpt;

Here you’ve added a property that you’ll hook up to a segmented control which will allow you to select one item from a list of options – perfect for selecting a quote type!

Now go to MainStoryboard.storyboard and drag a Segmented Control onto your view.

Adding a segmented control

Change the properties of the control to the following:

  • Style: Bar (my personal preference)
  • Segments: 3
  • Select Segment: 0 and change the title to: Classic
  • Select Segment: 1 and change the title to: Modern
  • Select Segment: 2 and change the title to: Mine

This achieves the effect of having three different quote types – or rather, the ability to select between one of the three.

Having created your Segmented Control, you need to link it to the outlet in your class. You can use the same method as before to hook up the control to the quoteOpt property on the View Controller.

You will not need an action event for this control.

Why don’t you build and run to see your new control on screen? It won’t do anything at the moment, but it’s nice to know it’s there!

Segmented control now appears

The Joy of Predicates

A predicate is a useful object that filters an array. It’s a bit like having a select with a simple where clause in SQL. I find them quite useful when I have a categorized property list. It saves you from having to create separate property lists.

Don’t hate me, but you have to go back and change quoteButtonTapped: in ViewController.m to use myQuotes instead of movieQuotes, as you will soon do something quite different for your movie quotes. And you need to put a condition around it, so that you’ll only use this when the third option is selected in the Segmented Control.

Or, if you prefer, simply replace quoteButtonTapped: with the following code:


-(IBAction)quoteButtonTapped:(id)sender {
    // 1 - Get personal quotes when the final segment is selected
    if (self.quoteOpt.selectedSegmentIndex == 2) {
        // 1 - Get number of rows in array
        int array_tot = [self.myQuotes count];
        // 2 - Get random index
        int index = (arc4random() % array_tot);
        // 3 - Get the quote string for the index
        NSString *my_quote = self.myQuotes[index];
        // 4 - Display the quote in the text view
        self.quoteText.text = [NSString stringWithFormat:@"Quote:\n\n%@",  my_quote];
    }
}

Now the user will see myQuotes only when they select the third option. As you’ll notice the rest of the code is the same as before, the only difference is that you display a quote (and that quote comes from the personal quote list) only when the segmented control has segment with index 2 selected. And as you might recall, since the segment control starts at index 0, index 2 means the third item.

Build and test your code to make sure that it works as you expect and that the quotes show up only when the “Mine” tab/segment is selected.

For the predicate fun, first you figure out the category you need based on the selected segment control and then use the category to create a filtered array of quotes that matches the category. Stay with me!

This is the code on the other side of the if statement in quoteButtonTapped: – so simply add this to the end of the method to complete the “if” statement begun in section #1:

// 2 - Get movie quotes
else {
    // 2.1 - determine category
    NSString *selectedCategory = @"classic";
    if (self.quoteOpt.selectedSegmentIndex == 1) {
        selectedCategory = @"modern";
    }
    // 2.2 - filter array by category using predicate
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"category == %@", selectedCategory];
    NSArray *filteredArray = [self.movieQuotes filteredArrayUsingPredicate:predicate];
    // 2.3 - get total number in filtered array
    int array_tot = [filteredArray count];
    // 2.4 - as a safeguard only get quote when the array has rows in it
    if (array_tot > 0) {
        // 2.5 - get random index
        int index = (arc4random() % array_tot);
        // 2.6 - get the quote string for the index
        NSString *quote = filteredArray[index][@"quote"];
        self.quoteText.text = [NSString stringWithFormat:@"Movie Quote:\n\n%@",  quote];
    } else {
        self.quoteText.text = [NSString stringWithFormat:@"No quotes to display."];
    }
}

Okay, build and run. Check that you see the right type of quote depending on your selection. If you are always getting the same type, my guess would be that you may not have linked the Segmented Control to your class.

The String Symphony

So far, so good! Now let’s explore some different string options and syntax in Objective-C.

If the quote has a source in the property list, then the app should display that as well. To check if there’s a value in a string, you can check the length of the string.

So add the following to quoteButtonTapped: after the first line in section #2.6 (the first line not counting the comment, that is):

// 2.7 - Check if there is a source    
NSString *source = [[filteredArray objectAtIndex:index] valueForKey:@"source"];
if (![source length] == 0) {
    quote = [NSString stringWithFormat:@"%@\n\n(%@)",  quote, source];
}
// 2.8 - Set display string

Also, comment out this line, you won’t need it anymore:

//self.quoteText.text = [NSString stringWithFormat:@"Movie Quote:\n\n%@",  quote];

You get the source from the array and check that it contains a value by making sure that its length is not zero. ! represents NOT. Use == when checking if an integer is equal to a value.

Then you build a new display string by combining the quote and the source using stringWithFormat.

To make things more interesting, why don’t you display something slightly different for quotes from classic movies that will involve checking the value of the category of the selected quote?

Replace section #2.8 in quoteButtonTapped: with the following:

// 2.8 - Customize quote based on category
if ([selectedCategory isEqualToString:@"classic"]) {
    quote = [NSString stringWithFormat:@"From Classic Movie\n\n%@",  quote];
} else {
    quote = [NSString stringWithFormat:@"Movie Quote:\n\n%@",  quote];
}
// 2.9 - Display quote
self.quoteText.text = quote;

This checks if the string is equal to a specific value, in this case “classic”, and customizes the label for the quote based on the category.

If you want to check for a particular movie title (or for that matter any other string attribute) starts with a particular value, you can do that too. Say you want to display some extra text if the quote is from a Harry Potter movie – add the following right above section #2.9:

if ([source hasPrefix:@"Harry"]) {
    quote = [NSString stringWithFormat:@"HARRY ROCKS!!\n\n%@",  quote];
}

As you can guess, hasPrefix is used to check if the start of the string has a particular text value.

Build and run your app to make sure that it works as you expect it to. Pay attention to the different categories and to Harry Potter movie quotes to make sure that it all works correctly.