Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Objective-C.Programming.pdf
Скачиваний:
14
Добавлен:
21.02.2016
Размер:
8.64 Mб
Скачать

For the More Curious: Manual reference counting and ARC History

[employees removeObjectAtIndex:5];

NSLog(@"allAssets: %@", allAssets);

NSLog(@"Giving up ownership of arrays");

allAssets = nil; employees = nil;

}

sleep(100); return 0;

}

Before you build and run your program, think about what you expect your output to look like. You’ll see the contents of the allAssets array – after Employee #5 has been deallocated. What will the status of Employee #5’s assets be at this point? These assets lose one owner (Employee #5), but they are still owned by allAssets, so they won’t be deallocated.

What about holder for the assets previously owned by Employee #5? When the object that a weak reference points to is deallocated, the pointer variable is zeroed, or set to nil. So Employee #5’s assets will not be deallocated, and their holder variables will be automatically set to nil.

Now build and run the program and check your output:

Employees: (

"<Employee 0: $0 in assets>",

...

"<Employee 9: $136 in assets>"

)

Giving up ownership of one employee deallocating <Employee 5: $136 in assets> allAssets: (

"<Laptop 0: $0, assigned to <Employee 3: $68 in assets>>", "<Laptop 1: $17, assigned to <Employee 6: $119 in assets>>", "<Laptop 2: $34, assigned to <Employee 7: $34 in assets>>",

"<Laptop 3: $51 unassigned>",

"<Laptop 4: $68, assigned to <Employee 3: $68 in assets>>",

"<Laptop 5: $85 unassigned>",

"<Laptop 6: $102, assigned to <Employee 6: $119 in assets>>", "<Laptop 7: $119, assigned to <Employee 2: $119 in assets>>", "<Laptop 8: $136, assigned to <Employee 9: $136 in assets>>", "<Laptop 9: $153, assigned to <Employee 1: $153 in assets>>"

)

Giving up ownership of arrays deallocing <Laptop 3: $51 unassigned>

...

deallocing <Laptop 8: $136 unassigned>

For the More Curious: Manual reference counting and ARC History

As mentioned at the beginning of Chapter 19, before automatic reference counting (ARC) was added to Objective-C, we had manual reference counting, which used retain counts. With manual reference counting, ownership changes only happened when you sent an explicit message to an object that decremented or incremented the retain count.

131

Chapter 20 Preventing Memory Leaks

[anObject release]; // anObject loses an owner [anObject retain]; // anObject gains an owner

You would see these sorts of calls primarily in accessor methods (where the new value was retained and the old value was released) and in dealloc methods (where all the previously retained objects were released). The setHolder: method for Asset would have looked like this:

- (void)setHolder:(Employee *)newEmp

{

[newEmp retain]; [holder release]; holder = newEmp;

}

The dealloc method would have looked like this:

- (void)dealloc

{

[label release]; [holder release]; [super dealloc];

}

What about the description method? It creates and returns a string. Should Asset claim ownership of it? That wouldn’t make sense; the asset is giving away the string it created. When you autorelease an object, you are marking it to be sent release in the future. Before ARC, the description method for Asset would look like this:

- (NSString *)description

{

NSString *result = [[NSString alloc] initWithFormat:@"<%@: $%d >",

[self label], [self resaleValue]];

[result autorelease]; return result;

}

When would it be sent release? When the current autorelease pool was drained:

// Create the autorelease pool

NSAutoreleasePool *arp = [[NSAutoreleasePool alloc] init]; Asset *asset = [[Asset alloc] init];

NSString *d = [asset description];

// The string that d points to is in the autorelease pool

[arp drain]; // The string is sent the message release

ARC uses the autorelease pool automatically, but you must create and drain the pool. When ARC was created, we also got a new syntax for creating an autorelease pool. The code above now looks like this:

// Create the autorelease pool @autoreleasepool {

Asset *asset = [[Asset alloc] init];

NSString *d = [asset description];

//The string that d points to is in the autorelease pool

}// The pool is drained

132

Retain count rules

Retain count rules

There are a set of memory management conventions that all Objective-C programmers follow. If you are using ARC, it is following these conventions behind the scenes for you.

In these rules, I 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 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 be 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 Asset class does not need to know anything about other objects that also care about its label. As long as an Asset instance retains objects it wants to keep, you won’t have any problems. Programmers new to 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.

Following the idea of ownership, now it becomes clear why you need to autorelease the string in your description method: The employee object created the string, but it doesn’t want to own it. It wants to give it away.

133

This page intentionally left blank

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]