How ARC does its work?

来源:互联网 发布:知乎怎么按点赞数排序 编辑:程序博客网 时间:2024/05/17 22:33

ARC does its work of inserting retain and release commands in two stages:

  1. It behaves very, very conservatively; basically, if in doubt, it retains — and of course it later releases. In effect, ARC retains at every juncture that might have the slightest implications for memory management: it retains when an object is received as an argument, it retains when an object is assigned to a variable, and so forth. It may even insert temporary variables to enable it to refer sufficiently early to an object so that it can retain it. But of course it also releases to match. This means that at the end of the first stage, memory management is technically correct; there may be far more retains and releases on a single object than you would have put if you were writing those commands yourself, but at least you can be confident that no pointer will dangle and no object will leak.
  2. It optimizes, removing as many retain and release pairs from each object as it possibly can while still ensuring safety with regard to the program’s actual behavior. This means that at the end of the second stage, memory management is still technically correct, and it is also efficient.

So, for example, consider the following code:

- (void) myMethod {

    NSArray* myArray = [NSArray array];

    NSArray* myOtherArray = myArray;

}

Now, in actual fact, no additional memory management code is needed here (for reasons that I’ll clarify in the next section). Even if you weren’t using ARC, you wouldn’t need to add any retain or release commands to this code. But in its first pass, we may imagine that ARC will behave very, very conservatively: it will ensure that every variable is nil or points to an object, and it will retain every value as it is assigned to a variable, at the same time releasing the value previously pointed to by the variable being assigned to, on the assumption that it previously retainedthat value when assigning it to that variable as well. So we may imagine (though this is unlikely to be exactly correct) a scenario where ARC compiles that code at first into the equivalent ofExample 12-1.

Example 12-1. Imaginary scenario: ARC’s conservative memory management

- (void) myMethod {

    // create all new object pointers as nil

    NSArray* myArray = nil;

    // retain as you assign, release the previous value

    id temp1 = myArray;

    myArray = [NSArray array];

    [myArray retain];

    [temp1 release]; // (no effect, it's nil)

    // create all new object pointers as nil

    NSArray* myOtherArray = nil;

    // retain as you assign, release the previous value

    id temp2 = myOtherArray;

    myOtherArray = myArray;

    [myOtherArray retain];

    [temp2 release]; // (no effect, it's nil)

    // method is ending, balance out retains on local variables

    // nilify when all remaining retains are balanced by release

    [myArray release];

    myArray = nil;

    [myOtherArray release];

    myOtherArray = nil;

}



The ARC optimizer will then come along and reduce the amount of work being done here. For example, it may observe that myArray and myOtherArray turn out to be pointers to the same object, so it may therefore remove some of the intermediate retains and releases. And it may observe that there’s no need to send release to nil. But retains and releases are so efficient under ARC that it wouldn’t much matter if the optimizer didn’t remove any of the intermediate retains and releases.

There’s more to the manual memory management balancing act than matching retain and release: in particular, I said earlier that alloc and copy yielded objects whose retain count had already been incremented, so that they, too, must be balanced by release. In order to obey this part of the rules of Cocoa memory management, ARC resorts toassumptions about how methods are named.

In particular, when your code receives an object as the returned value of a method call, ARC looks at the opening word (or words) of the camelCased method name. (The termcamelCased describes a compound word whose individual words are demarcated by internal capitalization, like the words “camel” and “Cased” in the word “camelCased.”) If the opening word of the name of that method isalloc, init, new, copy, or mutableCopy, ARC assumes that the object it returns comes with an incremented retain count that will need to be balanced with a corresponding release.

So, in the preceding example, if the array had been received from a call to [NSArray new] instead of [NSArray array], ARC would know that an extra release will be needed, to balance the incremented retain count of the object returned from a method whose name begins with new.

Your own responsibility in this regard, then, is not to name any of your methods inappropriately in such a way as to set off that sort of alarm bell in ARC’s head. The easiest approach is not to start any of your own method names with alloc, init (unless you’re writing an initializer, of course), new, copy, or mutableCopy. Doing so might not cause any damage, but it is better not to take the risk: obey the ARC naming conventions if you possibly can. (There are ways out of thispredicament if you have a wrongly-named method whose name you absolutely can’t change, but I’m not going to discuss them here.)


原创粉丝点击