Learn to Code iOS Apps 2: Strings, Arrays, Objects and Classes
Part 2 of a series where you’ll learn to code iOS apps using Apple’s development tools. For complete beginners – no prior programming experience needed! By Mike Jaoudi.
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
Learn to Code iOS Apps 2: Strings, Arrays, Objects and Classes
30 mins
C-Strings vs. NSString
You might be wondering why you had to convert the contents of cstring
to an NSString
. A simple list of characters is known as a “C string”. In the C language, which is the predecessor to Objective-C, the only way to store characters is by sticking them in a list. It’s efficient — but a little unwieldy when you want to manipulate that string data.
NSString
also stores a C string, but also provides a host of methods that allow you to do things such as get the string’s length and compare it to other strings.
Find the following line in your code:
NSLog(@"You entered the word '%@'", inputString);
…and change it to read as follows:
NSLog(@"You entered the word '%@' and it is %li characters long", inputString, [inputString length]);
Because inputString
is an object, it can receive messages such as length
, which causes it to report back the length of the string.
Run your app and enter a word. Your console session should look something like the following:
Please enter a word. objects You entered the word 'objects' and it is 7 characters long
Declaring an object like NSString
is significantly different from declaring a simple primitive variable type. Here is how inputString
is declared:
NSString *inputString = [NSString stringWithCString:cstring encoding:1];
NSString *inputString
simply creates an NSString
object named inputString
. The asterisk (*) that precedes the name of the object turns the variable into a pointer. A pointer just stores the memory location of the object — not the object itself. When declaring objects, they are always declared as pointers using the asterisk notation.
Note: Declaring an object pointer does not automatically create the object, which is different from primitive type variables. If you look at the code example above, everything to the right of the equals sign is what creates the object. If you don’t actually create the object that the pointer references, the pointer will literally point to nothing.
Note: Declaring an object pointer does not automatically create the object, which is different from primitive type variables. If you look at the code example above, everything to the right of the equals sign is what creates the object. If you don’t actually create the object that the pointer references, the pointer will literally point to nothing.
Why are pointers necessary? Objects can take up a lot of memory; it’s more efficient and convenient to pass around the memory address to where the object is stored. Otherwise you would be making huge in-memory copies of the object for everyone to use.
The need for pointers when working with objects goes a little deeper, but for now just remember that you always refer to objects through pointers.
Working with Classes and Objects
Your next task will be to create a simple database that keeps track of names and ages by using objects and custom classes.
To start, clear out everything in the @autoreleasepool
code block. The code in main.m should look like the following:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
}
return 0;
}
Think for a moment about how you will store each person’s record. It needs to contain their first name, their last name, and their age. Three pieces of data, all stored together — it sounds like a great use for an object, doesn’t it?
But there’s no predefined “Person” class in Objective-C. However, you can create your very own custom objects by defining a new class. A class is essentially a blueprint to say how an object should look and behave.
First, you’ll need to create a new file to hold your new class. In Xcode, navigate to File\New\File…, as shown below:
In the left column under OS X, select Cocoa. Then select Objective-C Class and click Next.
Set the class name to Person
and the Subclass to NSObject. Click the Next button and then click Create, as illustrated below:
In the file navigator on the left, you should see two new files: Person.h and Person.m.
Person.h is a rather small file. Open it; it will look like the following:
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
All files with the .h file extension are called header files. A header file tells the rest of the program about the elements in your class, such as variables and methods. The various portions of the header file are explained as below.
#import <Foundation/Foundation.h>
This is an import statement, which you’ve seen before. It simply imports the basic Foundation class which your app requires.
@interface Person : NSObject
The above line informs the rest of the program that you are making a class called Person
. The colon indicates that you are creating a subclass and the NSObject
part indicates the class you are subclassing from. NSObject
is a basic Objective-C class which can be used to represent an object. It has a few methods and properties which can prove useful in many different scenarios.
But you might be wondering what subclassing is. Subclassing is a way to derive a new class based on an existing class. The new class inherits all the existing attributes of the superclass (that’s the name given to the original class) but it can also define new attributes.
@end
The last line indicates that you are done defining the class. Everything between the @interface
line and the @end
line describes what is contained in the class.
Working with Instance Variables and Methods
Your Person
class needs to store three different things: the first name and last name will be strings, and the age will be an integer. Modify the @interface
block as shown below:
@interface Person : NSObject {
NSString *firstName;
NSString *lastName;
int age;
}
The curly braces surround the instance variables of the object. Each Person
object in your app has their own distinct set of data; they definitely don’t share names and ages! Instance variables store the individual characteristics of each object. Class variables, on the other hand, are shared amongst all objects of a particular class.
That takes care of storing a person’s data. Now what methods should your Person
class have? At a minimum, you’ll need to set and retrieve the person’s information.
Add these lines right above the @end
line:
- (void)enterInfo;
- (void)printInfo;
This defines the methods that your class provides to set the person’s data — enterInfo
— and to print the person’s data — printInfo
. You don’t need to flesh out the methods here in the header file; you just need to declare that they exist.
What does (void)
mean before each of these method declarations? Recall that int main
states that the return value of main
is of type int
. (void)
indicates that these methods don’t return anything to the caller.
That does it for the header file. Now open Person.m. The file should look like this:
#import "Person.h"
@implementation Person
@end
This is the implementation file where the source code for your class lives. Looking at the file line-by-line, you will see the following:
#import "Person.h"
This imports the class declarations from your header file, in exactly the same way that you imported the Foundation
classes in the header file.
@implementation Person
This indicates the start of the implementation block that contains the meat of your class.
@end
This simply indicates the end of the @implementation
block.
That implementation file looks pretty empty. Time to add some code! Add the following code after the @implementation
line:
- (void)enterInfo {
NSLog(@"What is the first name?");
char cstring[40];
scanf("%s", cstring);
firstName = [NSString stringWithCString:cstring encoding:1];
// more code for the other fields to come later...
}
- (void)printInfo {
NSLog(@"First name: %@", firstName);
}
The two methods above should look pretty familiar. enterInfo
will prompt the user to enter a first name and then store it in the firstName
instance variable. printInfo
uses the familiar NSLog
call to print out the stored first name.
This is a good time to test your class by calling it from the main
function. Open main.m and add the following line to the top of the file, immediately underneath the #import
line::
#import "Person.h"
By importing Person.h, you’ve told main
about the existence of your new Person
class.
Now add the following code just after the @autoreleasepool
line:
Person *newPerson = [[Person alloc] init];
[newPerson enterInfo];
[newPerson printInfo];
The first line in the code above creates a new Person
object. You’ll see the alloc / init
combination a lot in Objective-C; alloc
allocates memory for the object, while init
creates and initializes the object that will live at that memory address.
The next two lines send messages that call your new methods. The program will first ask the user to enter a first name and then print it back out to the console.
Run your project, and when prompted, enter a first name. Your console output should look similar to the following:
What is the first name? Michelle First name: Michelle
Hey, it looks like your object is working as designed! Now you just need to flesh out the rest of the implementation.
Open Person.m, and add the following lines below the comment // more code for the other fields to come later...
:
NSLog(@"What is %@'s last name?",firstName);
scanf("%s",cstring);
lastName = [NSString stringWithCString:cstring encoding:1];
NSLog(@"How old is %@ %@?", firstName, lastName);
scanf("%i", &age);
The code above prompts for the person’s last name and age and stores the data in the matching instance variables.
Finally, replace the printInfo
method’s NSLog
line with the following:
NSLog(@"%@ %@ is %i years old", firstName, lastName, age);
Run your project, and enter some data when prompted. Your output should look similar to the following:
What is the first name? Jane What is Jane's last name? Smith How old is Jane Smith? 23 Jane Smith is 23 years old
The Person
object is doing exactly what you would expect. However, the app only stores information for one person. That’s not too useful; you need to allow the user to enter information for as many people as they would like.