
Objective-C MVC or calculator for iOS 5
Background
Encouraged by the fact that in recent times I got into gear with devices, I decided to learn how to program for them. Of course, this will not help much in my chosen path of a web developer, but new languages have always been interesting to me.
The first thing my mind fell on was the iTunesU virtual school. Here I found CS 193P course lectures taught by Apple developers at Stanford University. Lectures cover the basic features of the language and native frameworks quite well, however there is one BUT - lectures in English and there is no translation for them. For me personally, this did not cause any problems, because Aple seems to choose only candidates with a well-delivered speech for these lectures, and those who lived in the USA for 8 months gave me the opportunity to watch the lectures in the original and study with “native speakers” (just kidding) .
Since a new version of Xcode is released every year, and Stanford's lectures on the current version are available late in the semester, I decided to write a series of articles that will go on the practical part (!) Of this course. Since I was listening to the lectures of autumn 2010, it will be practically useful for me to write a program in xcode 4.2 which was originally developed for version 3. Here I will not delve into ObjC especially, but will give bare practice.
So let's get started
For work I will use Xcode 4.2, iOS SDK 5 and all this will work under Mac OS X 10.7.2 Lion.
As you were told to notice from the title, I (read lecturer) will use the MVC data model. In general, to be honest, I don’t understand how I can code for iOS differently. We will write a program calculator. A simple calculator that will add, subtract, multiply, divide and extract the square root of numbers.
The structure of the program will be as follows:
1. we will have the brains of a calculator that will perform all the actions (brain class) - a model;
2. we will have a controller that will handle button clicks;
3. we will have a View, in which there are always problems with newly made iOS encoders. More on this later.
New project
So, let's start by creating a proct. To do this, go File - New - New project. Among the total set of templates, select "Single View Application". I will name the Calc application. It is also worth noting that when creating the project, I unchecked “Use Storyboard”. Why this is needed: in SDK 5, instead of the old .xib, a new .storyboard format has appeared. How they differ, I have not figured it out yet, so I use the xib files in the old fashion for IB (hereinafter Interface Builder).
So we have created a project. It already has a controller and view. To test the performance of the entire system, you can make a trial build. If everything is ok, then the iPhone emulator will appear on the screen and our application will start with a gray screen.
First, we need the brains of a calculator (processor) that will perform all the options. Press CMD + N and select the Objective-C class and call it the CalcBrain subclass of the NSObject class so that our brains inherit the basic methods. Now the project has two more files: CalcBrain.h and CalcBrain.m
Let's move on to ViewController.h. There you will not see anything except the import of the standard UIKit library and the declaration of the controller itself. Here we will need to declare the following things:
- outlets: variables that I will be tuking on certain elements of Interface Builder;
- actions: proper methods that will be called when IB elements perform certain actions.
- we also need to declare a variable of our new CalcBrain class to make this whole thing work.
So let's go.
#import
#import "CalcBrain.h"
@interface ViewController : UIViewController {
IBOutlet UILabel *display;
CalcBrain *brain;
}
-(IBAction)digitPressed:(UIButton *)sender; //++
-(IBAction)operationPressed:(UIButton *)sender; //++
@end
Here I will not explain anything, because the code can be intuitively understood (if not - alas, I advise you to read about OOP and other goodies of the programming world first).
Interface building
Now we digress a bit from the code and start building the interface. I believe that now it is necessary to focus all your attention, because in my experience a lot of beginning coders without a direct demonstration of actions just fell right
at this stage and gave up. Open ViewController.xib and see already existing objects:
Files's Owner - an object pointing to the class to which the given xib belongs (in our case, it is ViewController- this means that we can only use actions and outlets of only this controller);
First response
View - directly the representation of our controller.
First, create the buttons. Let's start with the numbers.

We create the first digit which in the future will be seven.

In order not to suffer further, we will immediately bind digitPressed action to our button. To do this, select our button and in the Connections Inspector take the braid that is opposite the Touch Down event and drag it to the File's Owner object.

A window will appear in which you can select the action to which the controller will respond when the button is touched.

We will need digitPressed.
All that remains for us is to breed our "button template" with Alt (options) held down. Now you can set labels on our numbers. This can be done either through the Attribute inspector or by double-clicking on the button. Also, do not forget that we have one button for separating the whole part from the fractional one (and this is done with the symbol "." And not "," as we do in Russia).

In the same way, we will make buttons for operations. We will understand the addition, subtraction, division, multiplication and extraction of the square root. And another equal sign that will output the result of our action. All. Now we have an input device. Delem output device, i.e. display. You need to create a Label object, align it to the left, set the font to 26 and default text “0”. Nothing complicated.


We continue to code
We will not deal with interfaces anymore. Remained clean code.
By the way, if you're interested, you can run the application and see how it will look on the emulator.
Let's start writing our brains. They will work like this:
1 The object will receive the first operand;
2 The object receives the action;
3 If the action is not taking the square root, we are preparing to receive the next operand;
4 If it is a root or we equate the result.
CalcBrain.h file text
#import
@interface CalcBrain : NSObject {
double operand;
}
-(void)setOperand:(double)aDouble;
-(double)performOperation:(NSString *)operation;
@end
With the operand variable, I hope there is no need to explain. Class methods - everything is just setOperand is a regular setter for the operand variable. It would be possible to use @syntesuze but then a getter will be generated which we do not need. So let’s get along with such a crutch. Now we will describe all our methods.
- (void)setOperand:(double)aDouble{
operand = aDouble;
}
- (double)performOperation:(NSString *)operation{
if ([operation isEqual:@"sqrt"]) {
operand = sqrt(operand);
}
return operand;
}
A little about the second method. The second method will process our action (the operation request is actually called that). For now, we are simply handling square root extraction. The input to this method will be the text from the operation button. Now we will struggle with the fact that the brain needs to memorize the first operand and the pressed operation before proceeding to memorize the second operand.
Let's add a class:
@interface CalcBrain : NSObject {
double operand;
NSString *waitingOperation;
double waitingOperand;
}
And description:
- (double)performOperation:(NSString *)operation{
if ([operation isEqual:@"sqrt"]) {
operand = sqrt(operand);
} else {
[self performWaitingOperation];
waitingOperation = operation;
waitingOperand = operand;
}
return operand;
}
The performWaitingOperation method will directly perform the action itself on the operands in case we have an action on more than one operand (sqrt).
-(void)performWaitingOperation {
if ([@"+" isEqual:waitingOperation]) {
operand = waitingOperand + operand;
} else if ([@"*" isEqual:waitingOperation]) {
operand = waitingOperand * operand;
} else if ([@"-" isEqual:waitingOperation]) {
operand = waitingOperand - operand;
} else if ([@"/" isEqual:waitingOperation]) {
if (operand) {
operand = waitingOperand / operand;
}
}
}
Unforgettable to declare this method in CalcBrain.h
Programmable controller
How proud it sounds. But it’s time to go to our controller, and specifically to the header file. Let's start describing our already declared methods. By the way, everything that Xcode created in the ViewController.m file can be erased. Till. For this application we will not need them. All we need:
#import "ViewController.h"
@implementation ViewController
-(IBAction)digitPressed:(UIButton *)sender {
}
-(IBAction)operationPressed:(UIButton *)sender {
}
@end
Now let's go through the methods. When clicking on the operation, we should get the text from the button. This is done simply: a button as an object with all parameters falls into the method:
-(IBAction)operationPressed:(UIButton *)sender {
NSString *operation = [[sender titleLabel] text];
}
Now we need to ask our brains to perform this operation. But first, we need to create these brains. We have allocated a variable for them but have not yet announced:
-(CalcBrain *)brain {
if (!brain) brain = [[CalcBrain alloc] init];
return brain;
}
And we’ll add the method of pressing the operation, make a reference request and display the result:
-(IBAction)operationPressed:(UIButton *)sender {
NSString *operation = [[sender titleLabel] text];
double result = [[self brain] performOperation:operation];
[display setText: [NSString stringWithFormat:@"%g", result]];
}
Now a logical problem arises - when the user presses “5” “5” then he means “55” and not “5” as our brains understand now. That is, we need a Boolean variable that will identify whether the user is in the input process or not.
@interface ViewController : UIViewController {
IBOutlet UILabel *display;
CalcBrain *brain;
BOOL userIsInTheMiddleOfTypingANumber;
}
Now you can describe the declaration of the operand when you press the operation key:
-(IBAction)operationPressed:(UIButton *)sender {
if (userIsInTheMiddleOfTypingANumber) {
[[self brain] setOperand:[[display text] doubleValue]];
userIsInTheMiddleOfTypingANumber = NO;
}
NSString *operation = [[sender titleLabel] text];
double result = [[self brain] performOperation:operation];
[display setText: [NSString stringWithFormat:@"%g", result]];
}
Now we describe the click on the number:
-(IBAction)digitPressed:(UIButton *)sender {
NSString *digit = [[sender titleLabel] text];
if (userIsInTheMiddleOfTypingANumber) {
[display setText:[[display text] stringByAppendingString:digit]];
} else {
[display setText:digit];
userIsInTheMiddleOfTypingANumber = YES;
}
}
Here the logic is simple: we get the number from the sender label, if stringByAppendingString is true, then we need to attach the entered number to the display. If not, just add a digit to the display and click the stringByAppendingString parameter.
Now only Build and Run is left.

Homework
You can add three functions:
Function ± which will turn the cisl from negative to positive;
Reset Reset Function (C);
And the function of repeating the operation (when I did the operation and pressed again = the last operation with the last operand is repeated);