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
Welcome to Part 2 of the Learn to Code iOS Apps series! This series introduces you to the basics of programming with the goal of creating an iOS app; no prior programming experience is required.
In the first tutorial in the series, you learned the basics of programming in Objective-C. Specifically:
- In Part 1, you learned the basics of Objective-C programming and you created a simple command line number guessing game.
- In Part 2 (You are Here!), you will learn about objects and classes in Objective-C and you will create a simple app to track people’s names and ages.
- In Part 3, the real fun begins! Now that you know the basics of programming, you will take all that you’ve learned and create a simple iPhone game of your own.
- In Part 4, you will take this app and make it beautiful, learning more about customizing the look and feel of iPhone apps.
Welcome to Part 2 of the Learn to Code iOS Apps series! This series introduces you to the basics of programming with the goal of creating an iOS app; no prior programming experience is required.
This part builds on the basic concepts that were covered in Part 1. If you haven’t worked through Part 1 yet and are new to programming or Objective-C, it’s highly recommended that you do so.
In this part you will learn about strings, arrays, classes, and objects in Objective-C. You will create will a Mac OS X app that keeps track of a list of people’s names and ages in order to learn these concepts.
These are fundamental building blocks that you will use in Part 3 of this series when you begin your iOS adventures in earnest and create your very first iPhone app!
Getting Started
This time you’re going to create a completely new project. You’ll choose a OS X command line app so you can continue to focus on the basics. Don’t worry – you’ll make an app with a user interface next time!
Start by launching Xcode and creating a new project by navigating to File\New\Project….
In the left column under OS X click on Application, select Command Line Tool, and click Next, as shown in the screenshot below:
Fill in the project options as follows:
- Product Name: PeopleDatabase
- Organization Name: This can be left blank.
- Company Identifier: Enter com.yourname
- Type: Foundation
- Use Automatic Reference Counting: Check this box
When you have finished filling out the information, the dialog should look similar to the one pictured below:
Just as in the previous project, you will add all your code inside the @autoreleasepool
block of main.m — right where the comment says insert code here
.
Working with Objects
Objective-C is known as an object-oriented language. But what is an object?
You’ve worked with variables containing primitive data types, such as int
, which holds an integer value. And that’s it. Primitive types don’t do anything beyond storing a single value.
However, objects extend this model by allowing multiple properties or values. For example, a button object might have a size, a color, and a label. Objects can also perform actions; for example, an image object could resize itself or draw itself on the screen.
Generally the type of an object is not referred to as a type, but rather a class. For example, consider the two following lines of code:
int age = 40;
NSString *name = @"Mike";
In plain language, you would describe age
as being “a variable of type int
“. However, you would describe name
as being “an object of class NSString
“, or alternately as “an instance of class NSString
“.
Note: Notice that there is a star (*) before the variable name this time. Whenever you create new objects, you always have to put a star when declaring the variable names. You can think of this as meaning “pointer to”, so you can say “name
is a pointer to an NSString
.”
Now that you understand the terminology, the best way to understand objects and classes is to dive right in and start using them.
Working with Strings
A string is used to store text; it can be a single letter, a word, phrase, or even an entire book’s worth of text!
Look at the NSLog
included in main.m:
NSLog(@"Hello World");
In this line of code, @"Hello World!"
is a string.
In Part 1 of this series, you printed out the value of an int
variable using NSLog
. You can also print out strings in the same manner.
Replace the NSLog(@"Hello World");
line with the following two lines of code:
NSString *helloString = @"Hello Variable!";
NSLog(@"%@", helloString);
The first line declares a helloString
variable which holds an object of class NSString
, which is the basic string class in Objective-C. (Don’t worry about the *
character for now; just remember that when you declare an object variable, you need to prefix the variable’s name with an *
.)
The second line is the now-familiar NSLog
statement. But this time, instead of using %i
as the format specifier, you use %@
to specify that you wish to print out a string.
Run your app; the output should say ‘Hello Variable!’.
Note: Why does everything in Objective-C seem to be prefixed with “NS”? When Steve Jobs left Apple in the mid-1980s he started a company called NeXT. NeXT created the Objective-C language along with an operating system called NeXTSTEP.
Objects in Objective-C were prefixed with “NS” — short for NeXTSTEP. When Apple bought NeXT in 1996, they developed OSX and iOS on top of the existing NeXTSTEP frameworks — and almost 20 years later, we’re all still using class names from the NeXT era.
String objects can store more than simple static content. Find the two following lines of code:
NSString *helloString = @"Hello Variable!";
NSLog(@"%@", helloString);
…and replace them with the following code:
int x = 10;
NSString *myString = [NSString stringWithFormat:@"The variable x stores the number %i", x];
NSLog(@"%@", myString);
Take a look at each line of code separately. The first line is pretty straightforward; it assigns a value of 10 to the int
variable x
.
The second line is a bit more involved. In Objective-C, you tell an object to perform an action by sending it a message. The square brackets indicate that a message will be sent to the receiving object. Inside the square brackets, the message receiver NSString
is stated first, followed by the stringWithFormat:
message.
The NSString
class will receive the message and then see if it knows what stringWithFormat:
means. Luckily, the programmers at Apple have included the stringWithFormat:
method in NSString. stringWithFormat:
simply creates a new string from a format string and some parameters.
A method is a task or operation that you want to execute; it’s a block of code stored somewhere else that you can execute to perform a specific task. Note the colon at the end of the method name stringWithFormat:
; everything following the colon is considered an argument to the method call.
Most object-oriented programming languages use the terminology “calling a method on an object” rather than “sending a message to an object”. Many Objective-C programmers use this terminology as well. Unless you want to get really picky, you can consider “calling methods” and “sending messages” to be the same thing.
Finally, the third line simply outputs the formatted myString
object to the console.
Run your project, and verify that the output reads as follows:
The variable x stores the number 10
In Part 1, you read in the user’s input using scanf
. Sadly, you can’t use scanf
to read in a string, as scanf
doesn’t work on objects. It works only on primitive datatypes such as:
- int
- float
- BOOL
- char
What to do?
Technically a string is made up of a sequence of individual characters. So to accept string input, you can read in the sequence of characters and convert it to a string.
Add the following code directly below the line NSLog(@"%@", myString);
:
NSLog(@"Please enter a word.");
// 1
char cstring[40];
// 2
scanf("%s",cstring);
// 3
NSString *inputString = [NSString stringWithCString:cstring encoding:1];
NSLog(@"You entered the word '%@'", inputString);
Here’s an explanation of the above code, comment by comment:
- You declare a variable called
cstring
to hold 40 characters. - You then tell
scanf
to expect a list of characters by using the%s
format specifier. - Finally, you create an
NSString
object from the list of characters that were read in.
Run your project; if you enter a word and hit Enter, the program should print out the same word you typed. Just make sure the word is less than 40 characters; if you enter more, you might cause the program to crash — you are welcome to test that out yourself! :]
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.
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.
Working with Sets of Objects
Think back to Part 1 — how did you solve this problem in your Higher and Lower game? Ah — you can use a looping structure to repeat the same bits of code until the user is done.
Replace the code in the @autoreleasepool
block in main.m with the following:
@autoreleasepool {
char response;
do {
Person *newPerson = [[Person alloc] init];
[newPerson enterInfo];
[newPerson printInfo];
NSLog(@"Do you want to enter another name? (y/n)");
scanf("\n%c", &response);
} while(response == 'y');
}
With this new code, in addition to asking for the name and age data, the program will now prompt the user to indicate if they are done. response
can holds either a ‘y’ or ‘n’, depending on the user’s response.
You may have noticed that this while loop looks a little different than the one you used in Part 1. That’s because this is known as a do-while
loop. The only difference here is that the looping condition is checked at the end of the loop, instead of at the beginning. This means that the code inside the loop will always execute at least once, regardless of the state of the looping condition.
Take a close look at the scanf
statement in the above code. There’s a strange “\n” in there. What does that mean?
\n
stands for “newline”, or the character that is printed when you hit the Enter key. It’s not a visible character, but scanf
will still pick it up when it parses the user’s input. So \n%c
is a special format specifier that tells scanf
to read in a character discarding newlines and other whitespace characters such as a space or tab.
The looping condition at the end of the block checks if response
is equal to the character ‘y’; if so, it loops back around. Note that the while condition has a semicolon after it; this is the only type of loop that requires a semicolon.
Run your project, and enter a few names and ages. As long as you keep typing “y”, the program will let you add another person. However, none of the names are being stored. Each time you go through the loop, a new Person
object is created and the previous one is lost.
How do you go about storing multiple Person
objects to retrieve later? You don’t want variables called person1
, person2
, person3
, and so on — you have no idea how many you’ll need. Instead, you need to store them in some kind of list. To do that, you’ll use an array.
Working with Arrays
Arrays are a way of storing a bunch of objects in a list. There are two types of arrays in Objective-C: NSArray
and NSMutableArray
. NSArray
is a basic static array; once you have created the array, you can’t add or remove items from it. This type of array is immutable, or unchangeable, much like many objects in Objective-C.
Conversely, NSMutableArray lets you add and remove items at any time. Since you will be adding an indeterminate number of people to the array over time, an NSMutableArray
is a good choice in this situation.
Find the line that declares the response
variable in main.m and add the following line directly below it:
NSMutableArray *people = [[NSMutableArray alloc] init];
The above line allocates and initializes a new NSMutableArray
object called people
.
Add the following line of code directly below the [newPerson printInfo];
line:
[people addObject:newPerson];
addObject:
is a method of NSMutableArray
that lets you add objects to the array. Now, each time you create a new Person
object, you don’t have to worry about it disappearing — you simply add it to your people
array so that it will remain in memory.
The storage mechanism of NSMutableArray
is demonstrated by the image below:
That solves the problem of storing the Person
objects — but how do you retrieve the objects once they’re stored? If you know the specific position, or index of the object in the array, you can reference the object by its index, as follows:
Person *theFirstPerson = people[0]
That code retrieves the first person in the array. Why are you using index “0” instead of “1”, you ask? Computers generally start indexing lists at zero, so the first element in the array is at position 0, the second element is at position 1, and so on.
In your app, you will loop through the array and print out all the stored names and ages only when the user has finished entering all of the data. This time you won’t use a while
or do
–while
loop — you’ll be using a for loop.
Add the following code after the line while (response == 'y');
:
NSLog(@"Number of people in the database: %li", [people count]);
for (Person *onePerson in people) {
[onePerson printInfo];
}
The NSLog
line will print out the number of Person
objects stored in the array using the count
property of NSMutableArray
.
The for
loop starts at the beginning of the array and executes the code contained in the curly braces for each object found in the array. This is pretty handy, since now you really don’t need to know beforehand how many Person
objects might be stored in the array.
Finally, the printInfo
method of your Person
object is used to print out each person’s information.
Run your project, and enter some information for a few people. When you are finished, the program will then neatly print out all of the people that you have stored in the array. Here’s a sample run of the program:
What is the first name? John What is John's last name? Appleseed How old is John Appleseed? 23 John Appleseed is 23 years old Do you want to enter another name? (y/n) y What is the first name? Albert What is Albert's last name? Einstein How old is Albert Einstein? 76 Albert Einstein is 76 years old Do you want to enter another name? (y/n) n Number of people in the database: 2 John Appleseed is 23 years old Albert Einstein is 76 years old
Where To Go From Here?
In this short tutorial, you have covered a fair bit of ground, including some rather complicated concepts in Objective-C:
-
do
–while
loops -
for
loops - Classes
- Objects
- Header files
- Implementation files
- Arrays
The best way to really understand Objective-C is to play around with your own code! Break it apart, add some more pieces, and put it back together; experimenting (and fixing things that you broke while experimenting) is the best way to learn how to program.
The final project with full source code can be found here.
Check out the next tutorial in the series, where you’ll put everything you learned so far to use, and create your first actual iPhone app!
If you have any questions or comments, feel free to raise them in the forums.
All videos. All books.
One low price.
A Kodeco subscription is the best way to learn and master mobile development — plans start at just $19.99/month! Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.
Learn more