Objectively Speaking 2: A Crash Course in Objective-C for iOS 6
This is the 2nd post by iOS Tutorial Team Member Linda Burke, an indie iOS developer and the founder of canApps. If you are a software developer skilled in another platform, but want to start learning iPhone development (and hence Objective-C) – this is the tutorial series for you! This tutorial picks up where the […] By .
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Objectively Speaking 2: A Crash Course in Objective-C for iOS 6
50 mins
- Getting Started
- Building Your Main View Controller
- Adding Labels and Buttons To Your View
- Adding the Quiz Logic
- Loading the Property List
- Creating the Property List File
- Iterating Through the Property List
- Providing Feedback Through the UI
- Adding Actions to Your Buttons
- Adding a New View
- Showing the Tips
- Adding a Segue Between Views
- Where to Go From Here?
Adding a New View
You might have noticed that the property list has tips
as one of its elements. This is where you implement the ability for the player to call up the “tip” screen and get a tip for the current question.
First, you’ll need to create the methods to keep track of the tip for each clue.
Add the following variables to Quiz.h at the end of the list of @property
declarations:
@property (nonatomic, assign) NSInteger tipCount;
@property (nonatomic, strong) NSString * tip;
The first variable keeps track of the number of tips, while the second stores the current tip.
Now you’ll need to initialize tipCount
to zero the first time through.
Add the following line to Quiz.m, at the end of the if
statement block in initWithQuiz
:
self.tipCount = 0;
You’ll also need to reset all the pertinent variables when the user moves on to the next question.
Next modify nextQuestion
in Quiz.m as follows:
- (void) nextQuestion: (NSUInteger) idx
{
self.quote = [NSString stringWithFormat:@"'%@'",self.movieArray[idx][@"quote"]];
self.ans1 = self.movieArray[idx][@"ans1"];
self.ans2 = self.movieArray[idx][@"ans2"];
self.ans3 = self.movieArray[idx][@"ans3"];
self.tip = self.movieArray[idx][@"tip"];
if (idx == 0) {
self.correctCount = 0;
self.incorrectCount = 0;
self.tipCount = 0;
}
}
In the code above, you first obtain the current tip, then set the quiz count to zero when the user is on the first question.
If the user has used up all of their allotted tips, then the tips button should not be available to the player.
To do this, move back to QuoteQuizViewController.m and add the following code to the end of nextQuizItem
:
if (self.quiz.tipCount < 3) {
self.infoButton.hidden = NO;
} else {
self.infoButton.hidden = YES;
}
Once tipCount
exceeds the three allotted tips, then you simply set the button's hidden
property to make it unavailable.
Showing the Tips
Now that all of the supporting modules have been created, you'll need to create a view controller to show the requested tips to the player.
To do this, go to File\New File…, choose the iOS\Cocoa Touch Class\Objective-C class template, and click Next. Name the new class QuizTipViewController and make it a subclass of UIViewController. Finally, click Next then Create.
Now you need to add a protocol to QuizTipViewController.h so that this class becomes a delegate.
Add the following code to QuizTipViewController.h just before @interface
:
@protocol QuizTipViewControllerDelegate;
A protocol allows classes to share similarly defined behavior. This is helpful when classes are not related to each other, but still behave in similar ways. In this way, classes do not need to "know" about one another, which reduces dependencies throughout your code.
Notice that the protocol has the word "delegate" in it. What's a delegate?
A delegate is an object that performs work on behalf of another object. For example, a foreman delegates the construction of a sidewalk to some of his workers in the same way an object may delegate the processing of information to another object. In this case, the class will notify another object that an event has occurred.
By using delegates with protocols, the delegator need not be concerned with the actual objects that are doing the work — so long as the work gets done! :]
Add the following code to QuizTipViewController.h between @interface and @end:
@property (nonatomic, assign) id <QuizTipViewControllerDelegate> delegate;
@property (weak, nonatomic) IBOutlet UITextView * tipView;
@property (nonatomic, copy) NSString * tipText;
When the user presses the "Done" button, QuizTipViewController will notify its delegate that the user is finished and the tip view should be dismissed. In this case, the delegate is QuizViewController which also is the presenter of QuizTipViewController.
Once QuizViewController is told that the "show is over", it will dismiss QuizTipViewController.
Add the following line of code to QuizTipViewController.h just before @end
:
- (IBAction)doneAction:(id)sender;
You're going to add a button that says "Done" on this view controller, and here you're declaring the method that you'll set up to be called when the button is tapped.
Finally, declare the rest of your protocol. While protocols can be contained in their own file, it is also common for developers to define them in the header file of the related class.
Add the following code to QuizTipViewController.h just after @end
:
@protocol QuizTipViewControllerDelegate
- (void)quizTipDidFinish:(QuizTipViewController *)controller;
@end
Here you say that any class that implements this protocol must implement one method, quizTipDidFinish:
.
Switch to QuizTipViewController.m. At the end of viewDidLoad
, add the following code:
self.tipView.text = self.tipText;
This will set the tipText field to the tip that was set in the class variable.
Next, add the following method to QuizTipViewController.m, just before the @end
declaration:
- (IBAction)doneAction:(id)sender
{
[self.delegate quizTipDidFinish:self];
}
Here you tell call the quizTipDidFinish
on the delegate method when the button is tapped.
Next, let's make the QuoteQuizViewController
implement the delegate.
Switch over to QuoteQuizViewController.h and add the import line for QuizTipViewController.h directly below the import statement for UIKit. Also add <QuizTipViewControllerDelegate>
to the end of the @interface
declaration to mark it as implementing the protocol, as shown below:
#import <UIKit/UIKit.h>
#import "QuizTipViewController.h"
@class Quiz;
@interface QuoteQuizViewController : UIViewController <QuizTipViewControllerDelegate>
@property (nonatomic, assign) NSInteger quizIndex;
@property (nonatomic, strong) Quiz * quiz;
- (IBAction)ans1Action:(id)sender;
- (IBAction)ans2Action:(id)sender;
- (IBAction)ans3Action:(id)sender;
- (IBAction)startAgain:(id)sender;
@end
Open QuoteQuizViewController.m and create quizTipDidMethod
— as defined by the protocol — by adding the code below just before the final @end
:
- (void)quizTipDidFinish:(QuizTipViewController *) controller {
[self dismissViewControllerAnimated:YES completion:^{}];
}
So when the user taps the done button, this delegate method gets called, and all you do is dismiss the view controller. You could do some more fancy work here if you wanted, like saving data.
Now it's time to add this new view controller to your user interface. Open the MainStoryboard.storyboard and drag in a new view controller, as shown in the screenshot below:
Select the new view controller and switch to the Identity Inspector (the third tab in). Under the Custom Class section, set the class field to be QuizTipViewController, as shown below:
Drag a label onto the view and place it near the top of the screen. Double-click the label and modify the label's text to be "Movie tip (3 tips only)". Center the label in the middle of the view.
Now drag in a textview under the label. Set the width to be 280 points, and the height to be 136 points.
Place a button underneath the textview, and make it the same width as the textview. Modify the text of the button to read "Done".
Your interface should now look like the following:
Right-click the Quiz Tip View Controller Scene, drag it to the text view, and then select the tipView
outlet. Next, right-click the Done button, drag it to the Quote Tip View Controller, and select doneAction
.
Now it is time to link up the two view controllers using a segue. First you will need a tip button — this will be the button that triggers the app to show the quiz tip view.
Scroll over to the previous view controller and select the "Next" button. Copy and paste the Next button, and drag this new button to the left side of the view controller. Modify the button's text to read Tip.
Since you copied the button, you also copied the actions associated with it. Right click the button, and click the 'X' button next to the action associated with "Touch Up Inside" action, to remove the action, as shown below:
We could have just dragged in a new button, but this is a common problem to run across so I wanted to show you it.
Finally, right-click Quote Quiz View Controller, drag over to the tip button, then select the infoButton
outlet.