When we look at the multitude of different apps available for the various iOS platforms it is easy to forget that at their core, the various Apple devices all work in binary. We as humans don’t think this way though and in order for us to program computers systems efficiently, we need a intermediate language that both we and the devices that we’re trying to program can understand.
Objective-C provides this language and at its core, contains a set of data types that allow us to design and build our applications in more abstract terms than the raw 1’s and 0’s that are understood by the hardware of the various Apple devices.
In this post, we’ll take a quick look at the concept of data types, the basic building blocks that we can use to build our applications, before taking a look at the range of types that are build into the Objective-C language.
Data Types
In computer science, a data type (often shortened to type) is a classification system that is used to specify the possible values that a particular piece of data can take.
The data type specifies how data is represented as binary 1’s and 0’s when it is stored in memory as well as how those 1’s and 0’s are interpreted when they are subsequently read back.
Data types also provide a mechanism by which the operations and manipulations that can be performed on values of a particular type can be specified. For example, it makes sense to be able to perform an operation that adds two numbers together, but what about adding two pictures? How about dividing two sounds?
By classifying the data in memory, data types provide a way of assigning higher-level meaning to the raw bits and bytes. This additional meaning allows us to write our apps in more abstract terms, terms that we as humans can understand. Using a relatively small set of data types along with the ability to create data types of our own we are able to express and structure almost any type of information we can imagine.
Primitive Types
For the most part, the basic data types (also known as primitive types) that are available in Objective-C are inherited from the C programming language, the language upon which Objective-C is built. In the next section we’ll take a brief look at some of the types that are available.
Primitive Data Types in Objective-C
Integer Types
We have already encountered the Objective-C data type int in previous posts. The int data type is short for integer and variables that have been declared as being of type int can be used to store integral or whole numbers (i.e. numbers that don’t contain a decimal point).
There are two main integer types that Objective-C inherits from C:
char int
The char
Data Type
The char data type is an 8-bit signed integer value and is commonly used to represent a single character, punctuation mark, space or symbol such as the letter ‘a’ or the ‘+’ symbol.
Escape Sequences
In addition to the characters, puntuation marks etc mentioned above, the char
data type can also store a range of special characters (often referred to as escape sequences) such as the tab or newline characters. These special characters all start with a backslash ( \
) followed by the special character. Commonly used special characters in Objective-C include:
a
– Sound alertb
– Backspacef
– Form Feedn
– Newliner
– Carriage Returnt
– Horizontal Tabv
– Vertical Tab\
– Backslash"
– Double Quote (when you want to include a double quote in a string – See later in this post for more on strings)'
– Single Quote (when you want to include a singe quote in a string).
The int
Data Type
The int
data type that we’ve already seen is larger than the char
data type in that it uses a larger number of storage bits (a minimum of 32-bits of storage instead of just 8). As with the char
data type, the int
data type is signed by default and with the extra bits, can store much larger numbers than can be stored in variables of type char
.
Type Prefixes
Now, these two basic integer data types (char
and int
) aren’t the only integer data types available to you in Objective-C. You also have the option of combining them with one or more type prefixes that modify whether variables of that type will be signed or unsigned (both the basic integer types are signed by default) as well as modifying how much storage the basic data types use in memory.
The valid type modifiers come in two groups.
In the first group we have the sign prefixes:
signed
– indicates that signed (i.e. both positive and negative) numbers will be stored. This modifier can be used with both thechar
andint
types.unsigned
– indicates that only positive numbers will be stored. This modifier can also be used with both thechar
andint
types.
In the second group we have the storage size prefixes:
short
– reduces the amount of storage used by the int type from 32-bits to 16-bits and is only valid when used in combination with the int data type.long
– increase the amount of storage used by the int type from its default of 32-bits. This modifier (currently) only has an effect on 64-bit iOS platforms and is only valid when used in combination with the int data type.long long
– increases the amount of storage used by theint
type from 32-bits to 64-bits. It is only valid when used in combination with theint
type.
Both the sign and storage size prefixes can also be used in combination. The example below shows a few potential valid combinations. When used in this way, the optional sign modifiers usually come first, followed by the optional length modifiers followed by the original integer data type:
unsigned char
signed int
unsigned short int
long int
unsigned long long int
Floating Point Types
Floating point numbers are numbers that have a decimal point and as we saw in my previous post on floating point numbers, values of this type are stored in memory as a combination of a sign-bit, mantissa and an exponent.
There are two primitive floating point types available in Objective-C:
- The
float
type is a 32-bit single precision float point value that uses a single sign bit, an 8-bit mantissa and 23 bits of exponent when storing numbers. This equates closely with the definition of a single-precision data type defined by the IEEE 754 specification that we looked at in my previous post. - The
double
type is used to store double-precision numbers (think IEEE 754 double-precision number) and uses twice the storage of thefloat
data type (a minimum of 64-bits). With thedouble
data type, the 64-bits are split into a single sign-bit, an 11-bit exponent and a 52-bit mantissa. With the additional bits, thedouble
type can be used to store the approximately twice the range of thefloat
data type.
One thing to notice is the floating point data types are all signed and due to the way that they are stored and we don’t have an option of changing this as we do with the integer data types. We do however, have the option of combining the double
data type with the same long
type prefix we saw in the previous section. In this combination, we can extend the amount of storage that variables of type double
use in memory from the default 64-bits up to 128-bits allowing us to store some seriously large numbers if we want to.
As with the integer types, when we want to declare a variable of a particular floating point data type, we declare the type (and any modifiers) followed by the variable name along with an optional initial value. Here are a couple of examples:
float standardGravity = 9.80665;
double goldenRatio = 1.61803398874;
long double pi = 3.14159265358979323846;
Arrays
Arrays represent a grouping of one or more contiguous areas in memory, all of which can store data with exactly the same data type and type modifiers. In a single variable declaration, arrays allow us to create areas in memory to store hundreds or even thousands of individual data items without the need to declare a separate variable for each one.
In addition to this arrays can also have multiple dimensions. Multi-dimensional arrays in C and Objective-C are defined as ‘arrays of arrays’ and at compile time all but the outermost array must have a fixed size.
We’ll look arrays more in a future post but for now imagine them as a set of pigeon holes, much like the picture to the right, with each pigeon hole being able to store an individual piece of data.
Strings (C-Style)
As well as all the other types we’ve looked at, Objective-C also inherits the concept of strings.
In C, a string is an array that contains one or more elements of type char
each of which represents a letter, number, symbol or white space followed by a terminating null character (which can be written as \n
) to indicate the end of the string. Strings are generally used to represent text such as the words, sentences and paragraphs on this page.
In Objective-C, we have the option of using C-style strings but most of the time, we tend to shy away from using them as libraries provided with Objective-C provide a higher-level, and more powerful string construct called NSString
that represents this sort of information.
Structs
Structures (also known as structs) are larger data types that consist of smaller types arranged in a specific ‘structure’ hence the name. As such, a struct
is a data type made up of other types and their power comes from the fact that we as programmers are able to define these structures for ourselves.
When we want to use a struct in our code, we first tell the compiler about how we want the individual members of that structure to be arranged. The definition of a structure has the following syntax:
struct struct_type {
member_type member_name;
member_type member_name;
} one_or_more_struct_variables_separated_by_commas;
As you can see, we have the keyword struct
followed by our name for the structure type. The type would be akin to the types we’ve been looking at up until now such as int
, char
, float
etc. This is followed by a pair of curly brackets within which we define the internal elements (known as members) of the struct.
Each member definition follows the same syntax that you will now be used to for declaring variables i.e. type followed by a variable (or in this case a member name). Let’s have a look at concrete example.
Imagine that I wanted to create a structure that represented the size (height / width) and position (say the the x and y locations of the top left hand corner) of a Rectangle drawn on the screen. We could define a struct to represent our rectangle as follows:
struct Rectangle {
unsigned short x; // Location of the top-left corner from the left of the screen.
unsigned short y; // Location of the top-left corner from the top of the screen.
unsigned short width; // The width of the rectangle.
unsigned short height; // The height of the rectangle.
} myRect;
This definition would result in a new datatype within our application called Rectangle
and a variable of that type called myRect
.
We can also create structures that themselves contain structures. If we had previously declared another structure type as follows:
struct Point { unsigned short x; unsigned short y; }
We could use that struct in our definition of our new Rectangle struct as follows:
struct Rectangle { Point position; unsigned short width; unsigned short height; }
Pointers
The last primitive data type we’re going to look at today are pointers. Pointers are data types that are used to hold a memory address. To distinguish them from a normal variable declaration they are declared using the asterisk character. For example, if we made the following variable declaration:
float *myPointer;
This tells the compiler that the myPointer variable is a pointer that references a memory location holding data of type float. The key thing to remember with pointers is that the pointer doesn’t hold the data itself. Instead it simply holds a reference to, (i.e. the address of) another location in memory of where the data is held. Pointers are extremely powerful concepts in C and Objective-C and we’ll take a more detailed look at them in future posts.
Source Image: https://flic.kr/p/deKzer