Home > Articles > Programming > General Programming/Other Languages

This chapter is from the book

Reference Counting

In the Cocoa Touch framework, Apple has adopted manual reference counting to manage memory and avoid premature deallocation and memory leaks.

To understand reference counting, imagine a puppy. When the puppy is born, it has an owner. That owner later gets married, and the new spouse also becomes an owner of that dog. The dog is alive because they feed it. Later on, the couple gives the dog away. The new owner of the dog decides he doesn't like the dog and lets it know by kicking it out of the house. Having no owner, the dog runs away and, after a series of unfortunate events, ends up in doggy heaven.

What is the moral of this story? As long as the dog had an owner to care for it, it was fine. When it no longer had an owner, it ran away and ceased to exist. This is how reference counting works. When an object is created, it has an owner. Throughout its existence, it can have different owners, and it can have more than one owner at a time. When it has zero owners, it deallocates itself and goes to instance heaven.

Using retain counts

An object never knows who its owners are. It only knows how many it currently has. It keeps track of this number in its retain count (Figure 3.2).

Figure 3.2

Figure 3.2 Retain count for a dog

When an object is created – and therefore has one owner – its retain count is set to one. When an object gains an owner, it is sent the message retain, and its retain count is incremented. When an object loses an owner, it is sent the message release, and its retain count is decremented. When that retain count reaches zero, the object sends itself the message dealloc, which returns all of the memory it occupied to the heap.

Imagine how you would write the code to implement this scheme yourself:

- (id)retain
{
    retainCount++;
    return self;
}
- (void)release
{
    retainCount--;
    if (retainCount == 0)
        [self dealloc];
}

Let's consider how retain counts work between objects by imagining you have a grocery list. You created it, so you own it. Later, you give that grocery list to your friend to do the shopping. You don't need to keep the grocery list anymore, so you release it. Your friend is smart, so he retained the list as soon as he got it. Therefore, the grocery list will still exist whenever your friend needs it, and he is now the sole owner of the list.

Here is your code:

- (void)createAndGiveAwayTheGroceryList
{
   // Create a list
   GroceryList *g = [[GroceryList alloc] init];

   // (The retain count of g is 1)

   // Share it with your friend who retains it
   [smartFriend takeGroceryList:g];

   // (The retain count of g is 2)

   // Give up ownership
   [g release];

   // (The retain count of g is 1)
   // But we don't really care here, as this method's
   // responsibility is finished.
}

Here is your friend's code:

- (void)takeGroceryList:(GroceryList *)x
{
    // Take ownership
    [x retain];

    // Hold onto a pointer to the object
    myList = x;
}

Retain counts can still go wrong in the two classic ways: leaks and premature deallocation. Continuing with the grocery list example, say you create and give a grocery list to your friend. He retains it, but you don't release it. Your friend finishes the shopping and releases the list. By now, you've forgotten where the list is, and since you never released it, its retain count is greater than zero – and now always will be. At this moment, nobody knows where this list is, but it still exists. This is a leak.

Think of the grocery list as an NSArray. You have a pointer to this NSArray in the method where you created it. If you leave the scope of the method without releasing the NSArray, you'll lose the pointer along with the ability to release the NSArray later. (You can't send a release message unless you know where to send it.) Even if every other owner releases the NSArray, it will never be deallocated, and the application can't use that memory for something else.

Consider the other way this process can go wrong – premature deallocation. You create a grocery list and give it to a friend who doesn't bother to retain it. When you release the list, it is deallocated because you were its only owner. Later, when your friend tries to use the list, he can't find it because it doesn't exist anymore.

This situation is worse that it sounds. Not only is your friend unable to do the shopping, but there are also application-level consequences to premature deallocation. When an object attempts to access another object that doesn't exist, your application accesses bad memory, starts to fail, and eventually crashes. On the other hand, if an object retains the objects it needs, then those objects are guaranteed to exist, and this type of disaster is avoided.

Reference counting is all about responsibility: if something creates an object, it is an owner of that object. Same goes for retaining an existing object. Releasing an object relinquishes that ownership. If something takes ownership of an object, it is responsible for relinquishing its ownership when it can no longer send messages to that object – when it no longer has a pointer to that object.

Let's make these ideas more concrete with an example from the RandomPossessions tool you wrote in the last chapter. Open RandomPossessions.xcodeproj and then open main.m in the editor area. In the main function, you created an instance of NSMutableArray named items. You know two things about this instance: the main function owns it, and it has a retain count of one. As an owner, it is main's responsibility to send this instance the message release when it no longer needs it. The last time you reference items in this function is when you print out all of its entries, so you can release it after that:

    for (Possession *item in items) {
         NSLog(@"%@", item);
    }
    [items release];
    items = nil;

When the message release is sent, the object pointed to by items decrements its retain count. In this case, the object is deallocated because main was its only owner. If another object had retained items, it wouldn't have been deallocated.

Using autorelease

You created items in main, use it there, and release it there. But what happens when you want to create an object to give out, not to own and use yourself?

This is often the case with convenience methods – class methods that return instances of the class. In the Possession class, you implemented a convenience method called randomPossession that returns an instance of Possession with random parameters. The Possession class owns this instance because it was created inside of a Possession class method, and the instance has a retain count of one.

However, the Possession class itself has no use for this instance; randomPossession is called by main where it returns the newly created Possession instance.

Should you release the Possession in main?

for(int i = 0; i < 10; i++)
{
    Possession *p = [Possession randomPossession];
    [items addObject:p];

    // Don't do this!
    [p release];
}

This is a very bad idea. The responsibility that is the core of reference counting includes not releasing objects that don't belong to you. That's like cancelling your friend's party. Or taking your neighbor's dog to the pound. If you don't own it, you shouldn't release it, and main does not own this Possession instance – it did not allocate it or retain it; it only has a pointer to it, courtesy of the randomPossession convenience method.

Releasing the possession is the responsibility of the Possession class, and it must be done in randomPossession before the pointer to it is lost when the scope of the method runs out. But where in randomPossession can you safely release the new Possession instance?

+ (id)randomPossession
{
    ... Create random variables ...
    Possession *newPossession = [[self alloc]
                        initWithPossessionName:randomName
                                valueInDollars:randomValue
                                  serialNumber:randomSerialNumber];


    // If we release newPossession here,
    // the object is deallocated before it is returned.
    return newPossession;

    // If we release newPossession here, this code is never executed.
}

What can you do? You need some way of saying "Don't release this object yet, but I don't want to be an owner of it anymore." Fortunately, you can mark an object for future release by sending it the message autorelease. When an object is sent autorelease, it is not immediately released; instead, it is added to an instance of NSAutoreleasePool. This NSAutoreleasePool keeps track of all the objects that have been autoreleased. Periodically, the autorelease pool is drained; it sends the message release to the objects in the pool and then removes them.

An object marked for autorelease after its creation has two possible destinies: it can either continue its death march to deallocation or another object can retain it. If another object retains it, its retain count is now 2. (It is owned by the retaining object, and it has not yet been sent release by the autorelease pool.) Sometime in the future, the autorelease pool will release it, which will set its retain count back to 1.

Sometimes the idea of "the object will be released some time in the future" confuses developers. When an iOS application is running, there is a run loop that is continually cycling. This run loop checks for events, like a touch or a timer firing. Whenever an event occurs, the application breaks from the run loop and processes that event by calling the methods you have written in your classes. When your code is finished executing, the application returns to the loop. At the end of the loop, all autoreleased objects are sent the message release, as shown in Figure 3.3. So, while you are executing a method, which may call other methods, you can safely assume that an autoreleased object will not be released.

Figure 3.3

Figure 3.3 Autorelease pool draining

The return value for autorelease is the instance that is sent the message, so you can nest autorelease messages.

// Because autorelease returns the object being autoreleased, we can do this:
NSObject *x = [[[NSObject alloc] init] autorelease];

At the end of randomPossession in Possession.m, autorelease the newly created instance so that the receiver of this object can choose to retain it or just let it be destroyed.

    Possession *newPossession =
        [[self alloc] initWithPossessionName:randomName
                              valueInDollars:randomValue
                                serialNumber:randomSerialNumber];

    return [newPossession autorelease];
}

Now, in main.m, when the main function asks the Possession class for a random possession, the class returns an autoreleased instance of Possession. At this point, nothing owns this instance. When the Possession is added to the items array, the array retains it, and it has a retain count of one.

for(int i = 0; i < 10; i++)
{
    // Get a new Possession instance - no one owns it as it's been autoreleased
    Possession *p = [Possession randomPossession];

    // Add p to the items array, it will retain that Possession
    [items addObject:p];
}

When will items release the Possession? When an NSMutableArray is deallocated, the objects it contains are released. Thus, when main (the sole owner of items) releases items, the NSMutableArray that items points to will release all its Possession instances (Figure 3.4). We've made sure these Possession instances had only items as an owner, so these instances will also be deallocated.

Figure 3.4

Figure 3.4 Deallocating an NSMutableArray

Here are three memory management facts to remember when working with instances of NSMutableArray:

  • When an object is added to an NSMutableArray, that object is sent the message retain; the array becomes an owner of that object and has a pointer to it.
  • When an object is removed from an NSMutableArray, that object is sent the message release; the array relinquishes ownership of that object and no longer has a pointer to it.
  • When an NSMutableArray is deallocated, it sends the message release to all of its entries.

Now let's turn to another place in RandomPossessions where you should use autorelease. In Possession.m, you override the description method of Possession's superclass. This method creates and returns an instance of NSString. Change the description method so that it returns an autoreleased string.

- (NSString *)description
{
    NSString *descriptionString =
        [[NSString alloc] initWithFormat:@"%@ (%@): Worth $%d, Recorded on %@",
                            possessionName,
                            serialNumber,
                            valueInDollars,
                            dateCreated];
    return [descriptionString autorelease];
}

You can make this even simpler by using a convenience method. NSString, like many other classes in the iOS SDK, includes convenience methods that return autoreleased objects – just like randomPossession does now. Modify description to use the convenience method stringWithFormat:. This ensures that the NSString instance that description creates and returns is autoreleased.

- (NSString *)description
{
    return [NSString stringWithFormat:@"%@ (%@): Worth $%d, Recorded on %@",
                            possessionName,
                            serialNumber,
                            valueInDollars,
                            dateCreated];
}

Accessors and memory management

Up to this point, our examples of ownership have been ownership by creation. When you want to own an object that you didn't create, you must retain it. For example, if an object has instance variables that point to other objects, that object should retain them. You can retain an object pointed to by an instance variable in the setter method for that variable.

Let's look at the instance variables of the Possession. Every instance of Possession has three instance variables that are pointers to other objects (possessionName, serialNumber, and dateCreated). Right now, the setter methods in Possession simply assign the incoming value to the instance variable:

- (void)setPossessionName:(NSString *)str
{
    possessionName = str;
}

Not good enough. If we give an NSString to a Possession for its possessionName, and the Possession doesn't retain it, then when we release the string, it will be destroyed. This is premature deallocation because the Possession still needs that string as its possessionName. The Possession will eventually send messages to or give out its possessionName. It will be embarrassing (and application-crashing) if the object that the variable points to doesn't exist.

Therefore, in a setter method, an object should retain the objects pointed to by its instance variables to make sure the objects continue to exist. Open Possession.m in the editor area. Modify the method setPossessionName: so that the Possession retains the string passed to it:

- (void)setPossessionName:(NSString *)str
{
    [str retain];
    possessionName = str;
}

The Possession will increment the retain count of the string passed to it, and no matter what happens to that string elsewhere in code, it will still exist until the Possession releases it.

Now let's look at what happens if you use the setter method to change the possessionName. For example, imagine we named a possession "White Sofa," and then a keen friend points out that it is actually off-white:

Possession *p = [[Possession alloc] init];
[p setPossessionName:@"White Sofa"];

// Wait, no it isn't...
[p setPossessionName:@"Off-white Sofa"];

Stepping through this code, p retains the string "White Sofa" and sets its possessionName to point at that string. Then, it retains the string "Off-white Sofa" and sets its possessionName to point at that string instead. This is a leak: the Possession lost its pointer to the "White Sofa" string but never released its ownership of it (Figure 3.5).

Figure 3.5

Figure 3.5 Sending a setter message more than once

Therefore, in a setter method, you retain the new object, release the object you currently have, and then make the assignment. Add the following line of code to this setter method in Possession.m.

- (void)setPossessionName:(NSString *)str
{
    [str retain];
    [possessionName release];
    possessionName = str;
}

You must retain the new object before releasing the current one. More often than you might imagine, possessionName and str will point at the same object. If you reverse the retain and release statements, you would release the object that you had planned to retain as the possessionName. Oops.

Now write the matching code for the method setSerialNumber: in Possession.m.

- (void)setSerialNumber:(NSString *)str
{
    [str retain];
    [serialNumber release];
    serialNumber = str;
}

What happens in these setter methods if the incoming argument or the current instance variable points to nil? If you pass nil as an argument in setPossessionName:, the Possession releases its current possessionName and sets its possessionName to nil. The result is the Possession has no possessionName. If you send setPossessionName: to a Possession that has no possessionName, you will send the release message to nil, which has no effect.

Note that we've only been changing setter methods. Getter methods do not need additional memory management. However, the object that sends the getter message may need to retain what is returned.

What about the other two instance variables? The dateCreated instance variable does not have a setter method; it is created and given its value in the designated initializer. Therefore, the instance of Possession already owns it, and it is ensured to exist. The valueInDollars instance variable needs no memory management because valueInDollars is a primitive and not an object.

Implementing dealloc

In the previous section, you released the object pointed to by possessionName when changing the name of a Possession. It is just as important to release the objects pointed to by a Possession's instance variables when the Possession is being deallocated.

When the retain count of a Possession instance hits zero, it will send itself the message dealloc. When the Possession instance is destroyed, its instance variables that are pointers to other objects are also destroyed (but not the objects they point to). Thus, you must ask yourself if the Possession owns these objects, and if it does, you must release them before these pointers are destroyed.

You own the objects pointed to by possessionName and serialNumber by virtue of retaining them in their setter methods. You also own dateCreated because you allocated it in the designated initializer for Possession.

Having established that you own these objects, you must release them before you lose your pointers to them. You can do this at the beginning of the dealloc method of Possession. In Possession.m, override dealloc to release the instance variables that the Possession owns.

   - (void)dealloc
   {
        [possessionName release];
        [serialNumber release];
        [dateCreated release];
        [super dealloc];
   }

Always call the superclass implementation of dealloc at the end of the method. When an object is deallocated, it should release all of its own instance variables first. Then, because you call the superclass's implementation, it goes up its class hierarchy and releases any instance variables of its superclass. In the end, the implementation of dealloc in NSObject returns the object's memory to the heap.

Why send release to instance variables and not dealloc? One object should never send dealloc to another. Always use release and let the object check its own retain count and decide whether to send itself dealloc.

Simplifying accessors with properties

Now that you've added memory management to your setter methods, let's look at a shortcut for creating accessor (both setter and getter) methods called properties. A property declares accessors for you in a header file. In Possession.h, replace the accessor declarations with properties.

@interface Possession : NSObject
{
    NSString *possessionName;
    NSString *serialNumber;
    int valueInDollars;
    NSDate *dateCreated;
}
+ (id)randomPossession;

- (id)initWithPossessionName:(NSString *)name
              valueInDollars:(int)value
                serialNumber:(NSString *)sNumber;

- (id)initWithPossessionName:(NSString *)name;


@property NSString *possessionName;
@property NSString *serialNumber;
@property int valueInDollars;
@property NSDate *dateCreated;


@end

Notice that properties are declared in the method area and not in the curly brackets with the instance variables. They also are, by convention, declared after class methods and initializers but before other instance methods.

Properties replace the accessor declarations, which saves a few lines of typing in the header file. But that's not all. You can also use properties to automatically generate the implementations of the accessor methods. You generate the accessors by synthesizing the property in the implementation file. But before we get to the actual synthesizing, we need to talk about property attributes.

Every property has a set of attributes that tailors the accessor methods it can generate. These attributes are listed in the property declaration. There are three categories of attributes:

atomicity

We will always use nonatomic for this attribute. There is rarely a reason to use the default, atomic, and the discussion of why is outside the scope of this book.

writability

By default, a property is readwrite. A readwrite property will generate a setter and getter method. The other option, readonly, only generates a getter method.

memory management

This attribute category only applies to the setter method. By default, a property is assign. In this case, a property's setter method only assigns the incoming argument to its instance variable. The other options are retain and copy, where the incoming argument is either retained or copied and then assigned to the instance variable. (We'll talk more about copy in a moment.)

In Possession.h, add attributes to the property declarations to match the current accessor implementations.

// The generated accessor methods for this property will be a getter
// and a setter that retains the incoming object and releases the old object.
@property (nonatomic, retain) NSString *possessionName;

// Ditto to the previous property
@property (nonatomic, retain) NSString *serialNumber;

// The generated accessor methods for this property will be a getter and a setter
// that simply assigns the incoming value to the ivar valueInDollars.
@property (nonatomic) int valueInDollars;

// The only generated accessor method for this property will be a getter.
@property (nonatomic, readonly) NSDate *dateCreated;

Now we can synthesize the properties in the implementation file. In Possession.m, remove all of the accessor method implementations and synthesize the properties instead.

@implementation Possession
@synthesize possessionName, serialNumber, valueInDollars, dateCreated;

Build and run the application. Everything should work the same as before.

Let's review what's changed here. Before, you explicitly declared and implemented all of your accessor methods. Now you've replaced the accessor declarations with property declarations and the accessor implementations with an @synthesize statement. The Possession keeps the same behavior with significantly less typing. In programming, whenever you can specify details and let the system do the work, it not only saves you typing, but it also helps prevent typos and other errors.

(So why did we make you type in all the accessors first instead of going straight to properties? It's important to understand what properties actually do. Too many new developers use properties without understanding the code behind them, and it trips them up later.)

There are a couple of additional points to make about properties. First, you do not have to synthesize a property. You can declare a property in the header file and implement the accessor methods yourself. This is useful for situations where you want to customize the accessors. You can also synthesize a property and implement one of the accessor methods; this overrides the method you replaced without affecting its partner.

Second, the name of a property does not have to match the name of the instance variable. In a synthesize statement, you can point a property at an instance variable of another name.

// This is just an example, don't type this code in.
@interface Possession : NSObject
{
    ...
}
@property (nonatomic, assign) NSString *name;
@end

@implementation Possession

@synthesize name = possessionName;
// This is equivalent to
// - (void)setName:(NSString *)str
// {
//      possessionName = str;
// }
// - (NSString *)name
// {
//      return possessionName;
// }
@end

This links the name property to the possessionName instance variable; therefore, when sending the message name to an instance of Possession, the value of possessionName is returned.

Finally, you don't even need an instance variable at all. When you synthesize a property, the compiler looks for an instance variable of the same name and if it finds one, it uses that instance variable. If a matching instance variable is not found, one is automatically created for you.

copy and mutableCopy

There are times when instead of retaining an object, you want to copy an object. When you send the message copy to an instance, a brand new instance is created that has the same values as the original instance. Copying an object gives you a brand new object with a retain count of one, and the retain count of the original object is unchanged. The object that sent the copy message is the owner of the new object.

You typically want to make a copy of an object if it is mutable. For example, an NSMutableArray is a mutable array. There is also an NSMutableString, a mutable subclass of NSString. Since NSMutableString "is a" NSString, it is conceivable that you could have an instance of NSMutableString as the possessionName of a Possession.

Imagine what would happen if an NSMutableString was set as the possessionName of a Possession. Another object that had a pointer to this string could change it, which would also change the name of the Possession. The Possession would have no idea this had happened.

NSMutableString *str = [[NSMutableString alloc] initWithString:@"White Sofa"];

// This is okay, as NSMutableString is a NSString since it is a subclass
[possession setPossessionName:str];

[str appendString:@" - Stained"];
// possession's name is now "White Sofa - Stained"

Typically, you do not want this behavior. Changing an object's instance variables without using an accessor is usually bad form. You can use copy to prevent the possibility of instance variables being changed behind your back.

In general, if a class has a mutable subclass, properties that are of the type of that class should have the attribute copy instead of retain. Then you will have a copy of the object that is all yours.

In Possession.h, change the memory management attribute of the two NSString properties to copy.

@property (nonatomic, copy) NSString *possessionName;
@property (nonatomic, copy) NSString *serialNumber;

The generated setter methods for these properties now look like this:

- (void)setPossessionName:(NSString *)str
{
    id t = [str copy];
    [possessionName release];
    possessionName = t;
}

When you copy an object, the copy returned is immutable. For instance, if you copy an NSMutableArray, the new object is simply an NSArray. (If you want a copy that can change, you must send the message mutableCopy instead.) Keep in mind, not all classes have mutable subclasses, and not all objects can be copied.

Congratulations! You've implemented retain counts and fixed the memory management problems in RandomPossessions. Your application now manages its memory like a champ!

Keep this code around because you are going to use it in later chapters.

Retain count rules

Let's make a few rules about retain counts to carry with us. In these rules, we use the word "you" to mean "an instance of whatever class you are currently working on." It is a useful form of empathy: you imagine that you are the object you are writing. So, for example, "If you retain the string, it will not be deallocated." really means "If an instance of the class that you are currently working on retains the string it will not be deallocated."

Here, then, are the rules. (Implementation details are in parentheses.)

  • If you create an object using a method whose name starts with alloc or new or contains copy, then you have taken ownership of it. (That is, assume that the new object has a retain count of 1 and is not in the autorelease pool.) You have a responsibility to release the object when you no longer need it. Here are some of the common methods that convey ownership: alloc (which is always followed by an init method), copy, and mutableCopy.
  • An object created through any other means – like a convenience method – is not owned by you. (That is, assume it has a retain count of one and is already in the autorelease pool, and thus doomed unless it is retained before the autorelease pool is drained.)
  • If you don't own an object and you want to ensure its continued existence, take ownership by sending it the message retain. (This increments the retain count.)
  • When you own an object and no longer need it, send it the message release or autorelease. (release decrements the retain count immediately. autorelease causes the message release to get sent when the autorelease pool is drained.)
  • As long as an object has at least one owner, it will continue to exist. (When its retain count goes to zero, it is sent the message dealloc.)

One of the tricks to understanding memory management is to think locally. The Possession class does not need to know anything about other objects that also care about its possessionName or serialNumber. As long as a Possession instance retains objects it wants to keep, you won't have any problems. Programmers new the language sometimes make the mistake of trying to keep tabs on objects throughout an application. Don't do this. If you follow these rules and always think local to a class, you never have to worry what the rest of an application is doing with an object.

Earlier in this chapter, we made changes to the accessor methods of Possession so they would properly handle memory management. Before that, the application ran perfectly fine. Why? The objects that were created and set as the instance variables of the Possession instances were never released. Therefore, it didn't matter if we retained them. However, in a real application, there are many more moving parts, and objects will be created and released. With proper memory management in place, this Possession class will now stand up in a real-world application.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020