What You’ll Learn in This Hour
Exploring the frameworks that extend Objective-C
Understanding Foundation policies and paradigms
Working with mutable classes
Using class clusters
Handling notifications
This book is about the Objective-C language; the Cocoa and Cocoa Touch frameworks are outside the scope of the book. However, the Foundation framework is relevant. The earliest guide to Objective-C, Object Oriented Programming: An Evolutionary Approach by Brad J. Cox (who codeveloped the language with Tom Love) was published in 1986. It describes Objective-C before the NeXT extensions and before the later extensions at Apple that culminated in OS X and iOS. The objects and methods listed in this book for the most part are still part of the language today. They were organized into collections in 1986; today they are organized into frameworks, a somewhat different structure, but still an organizing tool for objects.
These classes and methods are part of the language itself: Today, they are part of the Foundation framework (sometimes referred to simply as Foundation). They include the root class, NSObject
. The performSelector
method discussed at length in Hour 12, “Routing Messages with Selectors,” for example, is a method of NSObject
in the Cox book. Today, it has moved from NSObject
itself to the NSObject
protocol, but that is a relatively minor change.
The major Cocoa and Cocoa Touch frameworks are AppKit (OS X) and UIKit (iOS). These differ from the Foundation framework in that Foundation has nothing to do with the user interface. Thus, windows, views, and controls are not found anywhere in Foundation. There are a number of other Cocoa frameworks such as Core Data, Address Book, WebKit (only public in OS X), iAd (iOS only), and Preference Panes (OS X only). These are also beyond the scope of this book.
The complete Foundation Framework Reference is available on developer.apple.com as well as in Xcode (it is 2,000 pages long). This hour and others that follow provide a high-level road map and introduction.
There is a companion to the Foundation framework: the Core Foundation framework. They have similar structures and functionality, but Foundation is written in Objective-C, whereas Core Foundation is written in C. This was done in part to support the Carbon development environment that was a critical part of the transition from the C and C++ world of the Macintosh operating system to the Objective-C world of OS X. (By way of comparison, the Core Foundation Framework Reference is a mere 800 pages long.)
Foundation contains the classes that you use and subclass in your apps. There are two root classes along with a variety of other classes that are divided into groups.
NSObject
has been referred to as the root class for all other classes. In fact, it is one of two root classes—the other is NSProxy
, which is used with distributed objects. As the name suggests, it stands in for an object that may be distant or even may not be created yet. NSProxy
is a relatively recent addition to the world of Objective-C, and its addition caused a restructuring that has been alluded to previously.
The NSObject
protocol contains methods that formerly were part of the NSObject
class itself. By pulling a number of them out into the NSObject
protocol, all the root objects (that is, both of them) can share the functionality of the protocol.
Turning Part of a Class into a Protocol
Allocation, initialization, and duplication—You have already seen some of the commonly used methods in this area, such as alloc
and init
.
Introspection and comparison—You have seen respondsToSelector:
and instancesRespondToSelector:
as well as description
in other hours. Additional methods in this area include isEqual:
for testing two objects as well as the introspection methods class
and superclass
, which return the appropriate values as class objects (not strings).
Encoding and decoding—The methods in this area are used in archiving and unarchiving objects—converting them from objects in memory to byte streams that can be transmitted or written to files (and vice versa).
Message forwarding—This allows an object to forward a message it has received to another object.
Message dispatch—This includes the performSelector
methods described in Hour 12.
Object retention and disposal—Methods such as retain
, release
, autorelease
, retainCount
, and dealloc
let you manage memory for your objects.
GO TO Hour 16, “Managing Memory and Runtime Objects,” p. 221, for more on this topic as well as a discussion of Automatic Reference Counting (ARC), which eliminates the need for much manual memory management in object retention and disposal.
Beyond the root classes and their shared protocol, the other Foundation classes are divided into a number of groups. They provide object-oriented support for common programming tasks. The groups are the following:
Value objects—These include numbers, dates, and general data types.
XML support—These methods help you parse XML documents.
Strings—These methods include string classes themselves as well as support classes such as NSFormatter
.
Collections—These include arrays, dictionaries, and sets.
GO TO Hour 15, “Organizing Data with Collections,” p. 205, for more on collections.
Predicates—These methods help you construct predicates for use in selecting data.
Operating system services—Here, you find everything from spell checking to timers and NSError
.
File system—These routines manage files, metadata, and streams.
URL—These are the methods to connect to and download files by URL. They also include methods to handle cookies.
Interprocess communication—IPC has been a built-in component of Objective-C and Cocoa for many years. These methods implement pipes and ports among others.
Locking/threading—These methods let you manage multiple threads in your apps.
Notifications—The notification methods let you use the Objective-C messaging structure to keep track of events as they occur.
Objective-C language services—These include methods such as NSMethodSignature
, which was discussed in Hour 12 in the context of invocations.
Scripting—These are the methods to handle Apple events and script commands. They are implemented only on OS X.
Distributed objects—These methods are also only implemented on OS X. They are supported by NSProxy
, which is what led to the restructuring of NSObject
.
The common underpinnings of Foundation include implementation of policies and paradigms that are implemented across the other frameworks and in the code that you write. There are four sections of these paradigms and policies:
Mutability
Class clusters
Notifications
Garbage collection
GO TO Hour 16, “Managing Memory and Runtime Objects,” p. 221, for a discussion of garbage collection.
Many Foundation classes, such as NSArray
, NSSet
, NSString
, and NSData
, have mutable and immutable variants. Typically, the mutable variant is a subclass of the immutable one; the mutable subclass is identified by its name. For example, NSMutableArray
is the mutable variant of NSArray
. As you can imagine, this can make it possible for the compiler and runtime to optimize performance for the immutable variants.
If your changes to a mutable class are isolated to one or two methods (and that is often a good design), that can enable you to take advantage of the efficiencies of working with immutable variants. You can work with an immutable array or other class and, when you need to modify it, use mutableCopy
to make a mutable copy, modify it, and then use copy
to turn it back into an immutable object. (That is the default behavior for copy
.) You can then continue with the immutable copy.
Tip
Whether this type of switching between mutable and immutable variants is worthwhile or not depends on how much modifying you need to carry out compared with how much time it takes to copy the object in question.
Foundation makes use of class clusters that group hidden subclasses behind an abstract superclass with which you interact. The most commonly cited example of a class cluster is NSNumber
. There are hidden subclasses of the abstract NSNumber
class that are used for ints
, longlongs, chars
, and so forth. The init
methods of the abstract superclass dispatch the appropriate factory methods to create the appropriate hidden subclass as in the following code:
NSNumber *myInteger = [NSNumber numberWithInt: 1234];
Inside the abstract superclass NSNumber
, numberWithInt
creates a specific and hidden subclass that is an int
. You only see an NSNumber
, but it hides the various subclasses from you.
Tip
You can use this design pattern in your own code. It is an excellent way of implementing a variety of subclasses without revealing that they are separate subclasses.
Notifications provide a broadcast type of communication. Observers register to watch a certain event, and objects within your app post notifications. This is handled by a notification center that is part of each process.
Notifications are a very efficient low-level form of communicating information throughout your app. In many cases, they are an alternative to polling inside a loop to test whether or not something has happened. You just register to receive notifications about the event in which you are interested, and, assuming that you properly broadcast a notification when the event occurs, you find out that the event has occurred. There is no need for a polling loop to repeatedly check on what has or has not happened.
Notifications are subclasses of NSNotification
. There are three basic values, and you can add others if you need them. However, the basic NSNotification
structure is simple and very efficient.
Every notification has these three values:
name—This should be a unique name within the notifications for your app. Observers need to know it so that they can register for the type of notifications in which they are interested. This is an NSString
.
object—Typically, this is the object that posts the notification, but it need not be. It can even be nil
. This is an id
.
userInfo—This is a dictionary containing data relevant to the notification. It is up to you to define it and to let your observers know what is in it. This is an NSDictionary
.
It is important to note that the notification center for a process is the clearinghouse for notifications. Your process does not need to track observers. You just post notifications as necessary, and observers will receive them. You get the notification center for your process with the following snippet of code:
[NSNotificationCenter defaultCenter];
This snippet typically is used as part of a line of code that carries out a notification task, as you see in the following sections.
To create a new notification, you can use any of the two NSNotification
class methods:
+ (instancetype)notificationWithName:(NSString *)aName object:(id)anObject
+ (instancetype)notificationWithName:(NSString *)aName object:(id)anObject
userInfo:(NSDictionary *)userInfo
Your choice between them depends on whether you want simply to pass on a notification that something has happened (the first version) or a notification along with some relevant data (the second version) with the userInfo
dictionary.
More commonly, you use NSNotificationCenter
methods to create and post notifications in one step. Here are the three variations:
– (void)postNotification:(NSNotification *)notification
– (void)postNotificationName:(NSString *)notificationName
object:(id)notificationSender
– (void)postNotificationName:(NSString *)notificationName
object:(id)notificationSender userInfo:(NSDictionary *)userInfo
You need the notification center to use these methods, so a typical use of the first one might be:
[[NSNotificationCenter defaultCenter]
postNotificationName:(NSString *)notificationName];
You register to receive specific notifications (that is, to become an observer of the notification) with one of these NSNotificationCenter
methods.
This is the simplest way to add an observer. You specify the object to be notified, as well as the selector that is sent to that object. You further specify the name of the notification and, optionally, the sender of the notification. Either or both of notificationName
and notificationSender
can be nil; in those cases, notifications are delivered regardless of name and/or sender.
– (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector
name:(NSString *)notificationName object:(id)notificationSender
A typical example of registering to receive a notification would be:
[[NSNotificationCenter defaultCenter]
addObserver: myObserver selector: (SEL)mynotificationAction
name: nil notificationSender: nil];
GO TO Hour 20, “Working with Blocks,” p. 259, for more information on blocks.
Instead of using a selector, you can specify a queue and a block to add to it. The block takes one argument, which is the notification.
– (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue
*)queue
usingBlock:(void (^)(NSNotification *))block
When you no longer want to receive notifications, just remove the appropriate observer with one of these NSNotificationCenter
methods:
– (void)removeObserver:(id)notificationObserver
– (void)removeObserver:(id)notificationObserver name:
(NSString *)notificationName object:(id)notificationSender
A typical use would be:
[[NSNotificationCenter defaultCenter]
removeObserver: myObserver];
This hour has shown you the parts of the Objective-C language that are implemented in the Foundation framework. They include NSObject
(both the class and the protocol) as well as key functionalities, such as shared paradigms and policies. You have also seen key components of Foundation such as class clusters and their hidden subclasses as well as notifications.
Q. What do notifications accomplish?
A. They let you send messages to observers via a dispatch center. You post messages to the dispatch center, and it posts to the observers. You do not need a direct communication link to the observers.
Q. What is the purpose of class clusters?
A. These are related classes that frequently share a common abstract superclass. Developers use the methods of the abstract superclass, but in reality they are often manipulating the hidden internal subclasses. The abstract class’s initWith
methods frequently take care of creating the specific subclasses.
1. How many notification centers are there for each app?
2. What is the purpose of mutable and immutable classes?
1. There is one notification center for each app.
2. They can let you create optimized code for objects that will not be modified.
Explore the sample code for Core Recipes (OS X) and Core Data Books (iOS) to see notifications in action. Look at DocInteraction (iOS) to see how to receive process notifications when the files in a folder change.
3.141.197.251