Advertisement
iOS SDK

Exploring the Foundation Framework

by

The Foundation framework is the bread and butter in the toolbox of an iOS developer. It provides the NSObject root class and a large number of fundamental building blocks for iOS development, from classes for numbers and strings, to arrays and dictionaries. The Foundation framework might seem a bit dull at first, but it harnesses a lot of power and is indispensable when developing iOS applications.


A Word About Core Foundation

In the previous article, I briefly mentioned Core Foundation and its relation to Foundation. Even though we will not explicitly use the Core Foundation framework in the rest of this series, it's a good idea to be familiar with it and to know how it differs from the Foundation framework, which you'll use extensively.

While the Foundation framework is implemented in Objective-C, the Core Foundation framework is based on the C language. Despite this difference, the Core Foundation framework does implement a limited object model. This object model allows for the definition of a collection of opaque types that are often referred to as objects—despite the fact that they are, strictly speaking, not objects.

The primary goal of both frameworks is similar, enabling sharing of data and code between the various libraries and frameworks. Core Foundation also includes support for internationalization. A key component of this support is provided through the CFString opaque type, which efficiently manages an array of Unicode characters.

As I mentioned previously, toll-free bridging literally bridges the gap between both frameworks by enabling the substitution of Cocoa objects for Core Foundation objects in function parameters and vice versa.

It's important to note that Automatic Reference Counting (ARC) does not manage Core Foundation "objects", which means that you are responsible for managing memory when working with Core Foundation "objects". There is a great article by Mike Ash about Automatic Reference Counting and how to use ARC with Core Foundation and toll-free bridging.

Visit the Mac Developer Library for a complete list of the opaque types included in the Core Foundation framework.


Practice, Practice, Practice

Learning a new skill is best done through practice so create a new project in Xcode and select the Command Line Tool project template as we did earlier in this series. The Command Line Tool template can be found in the Application category in the OS X section. Click Next to continue.

Name the new project Foundation and enter an organization name and company identifier. For this project, it's key to set the project type to Foundation. Tell Xcode where you want to save the project and hit Create.

Test Drive

Our playground for the rest of this article will be main.m and the Xcode console window. Open main.m by selecting it in the Project Navigator in the left sidebar and make sure that the console window is visible by clicking the middle button of the View control in the Xcode toolbar.

Click the Run button in the top left to build and run the current scheme. If all went well, you should see Hello, World! appear in the console window at the bottom.


The Foundation Framework

The Foundation framework is much more than a collection of classes for working with numbers, strings, and collections (arrays, dictionaries, and sets). It also defines dozens of protocols, functions, data types, and constants.

In the rest of this article, I will primarily focus on the classes that you'll use most often when developing iOS applications. However, I will also briefly talk about three key protocols defined by the Foundation framework, NSObject, NSCoding, and NSCopying.

Header Files

As you already know, the header file of a class defines its interface. Does that mean that you have to import the header file of each Foundation class that you plan to use? The answer is yes and no.

It is indeed necessary to import the header file of a class before you can use it. You do so by adding an import statement as we saw earlier in this series. However, the Foundation framework provides a convenient way to facilitate this process. The only file you need to import is Foundation.h like shown in the following code snippet.

#import <Foundation/Foundation.h>;

Behind the scenes, the Foundation framework imports all the necessary header files to give you access to every class, protocol, function, data type, and constant of the Foundation framework.

Importing

When you create a new project in Xcode and you set the project type to Foundation, Xcode will:

  • link the project against the Foundation framework
  • add the above import statement to main.m
  • add the above import statement to the project's precompiled header file (*.pch)

Open main.m to verify this and expand the frameworks folder in the Project Navigator by clicking the small triangle on its left. I will revisit the precompiled header file and its purpose when we take a look at the UIKit framework.

Protocols

Several languages, such as Perl, Python, and C++, provide support for multiple inheritance, which means that a class can descend—be a subclass of—more than one class.

Even though Objective-C does not provide support for multiple inheritance, it does support multiple inheritance through specification in the form of protocols. What does this mean? Instead of inheriting from a class, a protocol defines a list of methods that classes implement if they conform to the protocol.

A protocol can have required and optional methods. If a class does not implement all the required methods of a protocol, the compiler will throw an error.

The benefits of protocols are manifold. When a class adopts or conforms to a protocol, the class is expected to implement the (required) methods declared in the protocol.

Objective-C protocols are very similar to interfaces in Java. This means that a protocol can be used to declare the interface to an object without revealing the class of the object.

Multiple inheritance has its benefits, but it most certainly has its downsides. The advantage of protocols is that unrelated classes can still share similar behavior through the use of protocols.

NSObject

In addition to the NSObject root class, the Foundation framework also defines a NSObject protocol. Objects conforming to the NSObject protocol can be asked about their class and superclass, can be compared with other objects, and respond to self as we saw in the article about Objective-C. This is only a small subset of the behavior added to objects conforming to the NSObject protocol.

NSCoding

Objects conforming to the NSCoding protocol can be encoded and decoded. This is necessary for objects that need to be archived or distributed. Object archival takes place when an object or object graph is stored to disk, for example.

NSCopying

The NSCopying protocol declares only one method, copyWithZone:. If a class is to support copying objects, it needs to conform to the NSCopying protocol. Copying an object is done by sending it a message of copy or copyWithZone:.


NSObject

The NSObject class is the root class of the vast majority of the Objective-C class hierarchies. Do you remember that we instantiated an instance of the Book class earlier in this series? We sent the Book class a message of alloc and we sent the resulting object a message of init. Both methods are declared in the NSObject class.

By inheriting from the NSObject root class, objects know how to behave as Objective-C objects and how to interface with the Objective-C runtime. It shouldn't be a surprise that NSObject conforms to the NSObject protocol that we saw earlier.

Remove the NSLog statement in main.m and paste the following code snippet in its place.

NSObject *myFirstObject = [[NSObject alloc] init];
NSLog(@"Class > %@", [myFirstObject class]);
NSLog(@"Superclass > %@", [myFirstObject superclass]);
NSLog(@"Conforms to Protocol > %i", [myFirstObject conformsToProtocol:@protocol(NSObject)]);

We start by instantiating an instance of NSObject and store a reference to it in the myFirstObject variable. In the second line, we log the class name of the new object to the console. The class method, returns an instance of NSString, a string object, which is the reason that we use the %@ format specifier in the NSLog statement.

Next, we ask myFirstObject for its superclass and end by verifying that myFirstObject conforms to the NSObject protocol. Are you confused by @protocol(NSObject)? This is nothing more than a reference to the NSObject protocol.

Click Run and inspect the output in the console window. Are you surprised by the output? Because NSObject is a root class, it doesn't have a superclass.


NSNumber

The NSNumber class is a utility class that manages any of the basic numeric data types. It is a subclass of the NSValue class, which provides an object oriented wrapper for scalar types as well as pointers, structures, and object ids. The NSNumber class defines methods for retrieving the value it stores, for comparing values, and also for retrieving a string representation of the stored value.

Keep in mind that the value retrieved from an NSNumber instance needs to be consistent with the value that was stored in it. The NSNumber class will attempt to dynamically convert the stored value to the requested type, but it goes without saying that there are limitations inherent to the data types that NSNumber can manage.

Let me illustrate this with an example. Add the following code snippet to main.m.

NSNumber *myNumber = [NSNumber numberWithDouble:854736e+13];
NSLog(@"Double Value    > %f", [myNumber doubleValue]);
NSLog(@"Float Value     > %f", [myNumber floatValue]);
NSLog(@"Int Value       > %i", [myNumber intValue]);

We start by creating a new NSNumber instance by passing a double value to numberWithDouble:. Next, we retrieve the stored value using three different NSNumber methods. The results don't reflect the value stored in myNumber for obvious reasons.

The lesson is simple, be consistent when using NSNumber by keeping track of the type that is stored in the NSNumber instance.


NSString

Instances of the NSString class manage an array of unichar characters forming a string of text. The subtle but important difference with a regular C string, which manages char characters, is that a unichar character is a multibyte character.

As its name implies, a unichar character is ideally suited for handling Unicode characters. Due to this implementation, the NSString class provides out-of-the-box support for internationalization.

I want to emphasize that the string managed by a NSString instance is immutable. This means that once the string is created, it cannot be modified. Developers coming from other languages, such as PHP, Ruby, or JavaScript, might be confused by this behavior.

The Foundation framework also defines a mutable subclass of NSString, NSMutableString, which can be modified after it's been created.

There are various ways to create string objects. The simplest way to create a string object is by calling the string method on the NSString class, which returns an empty string object. Take a look at the class reference of NSString for a complete list of initializers.

Another common path for creating string objects is through string literals as shown in the example below. In this example, a literal string is assigned to the someString variable. At compile time, the compiler will replace the string literal with an instance of NSString.

NSString *string1 = @"This is a string literal.";

The NSString class has a multitude of instance and class methods for creating and manipulating strings and you will rarely, if ever, feel the need to subclass NSString.

Let's explore NSString and its mutable subclass, NSMutableString, by adding the following snippet to main.m.

NSString *string1 = @"This is a string literal.";
NSString *string2 = [[NSString alloc] initWithFormat:@"Strings can be created many ways."];
NSMutableString *mutableString = [[NSMutableString alloc] initWithString:string1];
[mutableString appendFormat:@" %@", string2];
NSLog(@"%@", mutableString);

We start by creating a string object using a string literal. In the second line, we create a second string by using one of the specialized initializers that NSString provides. A mutable string is then created by passing the first string as an argument. To illustrate that mutable strings can be modified after creation, string2 is appended to the mutable string and logged to the console window.


NSArray and NSSet

The NSArray class manages an immutable, ordered list of objects. The Foundation framework also defines a mutable subclass of NSArray, NSMutableArray. The NSArray class behaves very much like a C array with the difference that an instance of NSArray manages objects. In addition, NSArray declares a wide range of methods that facilitate working with arrays, such as methods for finding and sorting objects in the array.

It's important to understand that instances of NSArray, NSSet, and NSDictionary can only store objects. This means that it's not possible to store scalar types, pointers, or structures in any of these collection classes—or their subclasses—the compiler will throw an error if you do. The solution is to wrap scalar types, pointers, and structures in an instance of NSValue or NSNumber as we saw earlier in this article.

Add the following code snippet to main.m to explore NSArray and its mutable counterpart, NSMutableArray.

NSArray *myArray = [NSArray arrayWithObjects:@"Bread", @"Butter", @"Milk", @"Eggs", nil];
NSLog(@"Number of Elements  > %li", [myArray count]);
NSLog(@"Object at Index 2   > %@", [myArray objectAtIndex:2]);

NSMutableArray *myMutableArray = [NSMutableArray arrayWithObject:[NSNumber numberWithInt:265]];
[myMutableArray addObject:[NSNumber numberWithInt:45]];
NSLog(@"Mutable Array       > %@", myMutableArray);

In the first line, we create an array by using the arrayWithObjects: class method. This method accepts a variable number of arguments—objects—with the last argument being nil—which is not included in the array. In the second and third line, we query the array for the number of objects in the array and the object stored at index 2 respectively.

Because NSMutableArray inherits from NSArray, it behaves in much the same way as NSArray. The main difference is that objects can be added and removed from the array after it's been created.

Before moving on, I want to say a few words about NSSet. This class is similar to NSArray, but the key differences are that the collection of objects that a set manages is unordered and duplicates are not allowed.

The advantage of NSSet is that querying its objects is faster if you only need to know if an object is contained in the set. The Foundation framework also defines NSOrderedSet. Instances of this class have the benefits of NSSet, but also keep track of the position of each object.


NSDictionary

Like arrays, dictionaries are a common concept in most programming languages. In Ruby, for example, they are referred to as hashes. The basic concept is easy, a dictionary manages a static collection of key-value pairs or entries.

As in Ruby hashes, the key of an entry doesn't need to be a string object per se. It can be any type of object that conforms to the NSCopying protocol as long as the key is unique in the dictionary. In most cases, though, it's recommended to use string objects as keys.

Like arrays, dictionaries cannot store a null value. If you want to represent a null value, then you can use NSNull. The NSNull class defines a singleton object that is used to symbolize null values in arrays, dictionaries, and sets.

The singleton pattern is an important pattern in many programming languages. It limits the instantiation of a class to one object. You will deal with singleton objects frequently when developing iOS applications.

Like NSArray, the Foundation framework defines a mutable subclass of NSDictionary, NSMutableDictionary. There are various ways to instantiate a dictionary. Take a look at the following code snippet.

NSString *keyA = @"myKey";
NSString *keyB = @"myKey";
NSDictionary *myDictionary = [NSDictionary dictionaryWithObject:@"This is a string literal" forKey:keyA];
NSLog(@"%@", [myDictionary objectForKey:keyB]);

We first declare two separate string objects containing the same string. In the third line, we instantiate a dictionary by calling the dictionaryWithObject:forKey: method on the NSDictionary class.

Next, we ask the dictionary for the object associated with the contents of keyB and log it to the console.

It's important to pay attention to the details. Even though we used keyA as the key of the key-value pair and keyB as the key to fetch the value or object of the key-value pair, the dictionary gave us the correct object. The NSDictionary class is smart enough to know that we want the object associated with string myKey. What does this mean? Even though the objects keyA and keyB are different objects, the string that they contain is the same and that is precisely what the NSDictionary class uses to reference the object.

The following code fragment shows that a dictionary can contain another dictionary—or array—and it also shows how to work with mutable dictionaries.

NSMutableDictionary *myMutableDictionary = [NSMutableDictionary dictionary];
[myMutableDictionary setObject:myDictionary forKey:@"myDictionary"];
NSLog(@"%@", myMutableDictionary);

Objective-C Literals

Earlier in this article, I introduced you to Objective-C string literals, such as @"This is a string literal.". They take the form of a C string literal prefixed with an @ sign. As you probably know by now, the @ sign indicates that we are entering Objective-C territory.

An Objective-C literal is nothing more than a block of code that references an Objective-C object. With the release of Xcode 4.5, you can now also use Objective-C literals for NSNumber, NSArray, and NSDictionary. Take a look at the following code snippet to see how this works.

NSNumber *oldNumber1 = [NSNumber numberWithBool:YES];
NSNumber *newNubmer1 = @YES;

NSNumber *oldNumber2 = [NSNumber numberWithInt:2147];
NSNumber *newNubmer2 = @2147;

NSArray *oldArray = [NSArray arrayWithObjects:@"one", @"two", @"three", nil];
NSArray *newArray = @[@"one", @"two", @"three"];

NSDictionary *oldDictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:12345] forKey:@"key"];
NSDictionary *newDictionary = @{@"key": @12345};

Not only are Objective-C literals cool and sexy, they also make your code more readable. Mark Hammonds wrote a tutorial about Objective-C literals. Read Mark's post for a more complete overview of Objective-C literals.


Logging with NSLog

In this article, we have repeatedly used the NSLog function, which is defined by the Foundation framework. NSLog accepts a variable number of arguments with the first argument being a string literal. The string literal can contain format specifiers that are replaced by the extra arguments passed to the NSLog function.

NSLog(@"%@ - %i - %f", @"an object", 3, 3.14);

Visit the Mac Developer Library for a complete list of the format specifiers that can be used.


Conclusion

Even though we have covered a lot of ground in this article, we've barely scratched the surface of what the Foundation framework has to offer.

It isn't necessary to know the details of every class or function defined in the Foundation framework to get started with iOS development, though. You'll learn more about the Foundation framework as you explore the iOS SDK.

In the next article, we'll explore the UIKit framework and I will also discuss the ins and outs of an iOS application.

Related Posts
  • Code
    iOS SDK
    Working with NSURLSession: Part 3E548b preview image@2x
    In the previous tutorials, we explored the fundamentals of the NSURLSession API. There is one other feature of the NSURLSession API that we haven't look into yet, that is, out-of-process uploads and downloads. In the next two tutorials, I will show you how to create a very simple podcast client that enables background downloads.Read More…
  • Code
    iOS SDK
    Objective-C Succinctly: Blocks0e5ds8 preview image@2x
    Blocks are actually an extension to the C programming language, but they are heavily utilized by Apple's Objective-C frameworks. They are similar to C#'s lambdas in that they let you define a block of statements inline and pass it around to other functions as if it were an object.Read More…
  • Code
    iOS SDK
    Objective-C Succinctly: Exceptions and Errors0e5ds8 preview image@2x
    In Objective-C, there are two types of errors that can occur while a program is running. Unexpected errors are "serious" programming errors that typically cause your program to exit prematurely. These are called exceptions, since they represent an exceptional condition in your program. On the other hand, expected errors occur naturally in the course of a program's execution and can be used to determine the success of an operation. These are referred to as errors.Read More…
  • Code
    iOS SDK
    Objective-C Succinctly: Protocols0e5ds8 preview image@2x
    In Objective-C, a protocol is a group of methods that can be implemented by any class. Protocols are essentially the same as interfaces in C#, and they both have similar goals. They can be used as a pseudo-data type, which is useful for making sure that a dynamically-typed object can respond to a certain set of messages. And, because any class can "adopt" a protocol, they can be used to represent a shared API between completely unrelated classes.Read More…
  • Code
    iOS SDK
    Objective-C Succinctly: Data Types0e5ds8 preview image@2x
    Objective-C has two categories of data types. First, remember that Objective-C is a superset of C, so you have access to all of the native C data types like char, int, float, etc. Objective-C also defines a few of its own low-level types, including a Boolean type. Let's call all of these "primitive data types."Read More…
  • Code
    iOS SDK
    Objective-C Succinctly: Hello Objective-C0e5ds8 preview image@2x
    This chapter is designed to help you acclimate to Objective-C programming style. By the end of this chapter, you will be able to instantiate objects, create and call methods, and declare properties. Remember that the goal is to provide a very brief survey of the major object-oriented aspects of Objective-C, not a detailed description of each component. Later chapters fill in many of the conceptual details omitted from this chapter.Read More…