IOS4 note 13 (3)

 

Instance Variable Memory Management Policies

In the preceding section, we saw that an instance variable might be set by retaining or copying  the  incoming  value. There  are  in  fact  three possible memory-management policies for an instance variable:

retain

The incoming value is retained (and the existing value is released).

copy

The  incoming value  is copied (and the existing value  is released). This policy  is typical where the class of the instance variable is an immutable class with a mutable subclass (such as NSString, NSArray, or NSDictionary), in case we are handed a mutable instance that might be subsequently mutated by some other object.

assign

The incoming value is directly assigned to the instance variable; it is not retained, nor is the existing value released. This policy is followed when it would be wrong

for us to assert ownership of the incoming object. For example, an object would not normally retain its delegate.

 

The “assign” policy must also be used to prevent a retain cycle, a situation in which two objects retain each other. This must never be allowed to happen, because both objects will leak (neither can have its retain count reach zero by normal means). For example, in a system of orders and items, an order needs to know what its items are and an item might need to know what orders it is a part of, but it must not be the case both that an order retains its items and that an item retains its orders.

Note that you must not release, in dealloc, an instance variable whose policy is “assign.”You would be releasing something you never retained or generated by copying, which is a no-no (and a likely crasher).

 

 

Autorelease

Here’s how autorelease works. Your code runs in the presence of something called an autorelease pool. (If you look in main.m, you can actually see such one such pool being created.) When you send autorelease to an object, that object is placed in the autorelease pool, and a number is incremented saying how many times this object has been placed in this autorelease pool. From time to time, when nothing else is going on, the autorelease pool is automatically destroyed and replaced by another. At the moment when an autorelease pool is destroyed, it sends release to each of its objects, the same number of times as that object was placed in this autorelease pool. This is called draining the pool. If that causes an object’s retain count to be zero, fine; the object is destroyed in the usual way. So autorelease is just like release — effectively, it is a form of release — but with a proviso, “later, not right this second.”

 

Sometimes you may wish to drain the autorelease pool immediately. Consider the following:

for (NSString* aWord in myArray) {

    NSString* lowerAndShorter = [[aWord lowercaseString] substringFromIndex:1];

    [myMutableArray addObject: lowerAndShorter];

}

 

Every time through that loop, two objects are added to the autorelease pool: the low-ercase version of the string we start with, and the shortened version of that. The first object, the lowercase version of the string, is purely an  intermediate object: as the current iteration of the loop ends, no one except the autorelease pool has a pointer to it. If this loop had very many repetitions, or if these intermediate objects were themselves very large in size, this could add up to a lot of memory. These intermediate objects will all be released when the autorelease pool drains, so they are not leaking; nevertheless, they are accumulating in memory, and in certain cases there could be a danger that we will run out of memory before the autorelease pool drains. The problem can be even more acute than you know, because you might repeatedly call a built-in Cocoa method that itself accumulates a lot of intermediate objects.

 

When you release an autorelease pool, it is drained, so the objects it contains are sent release then and there:

for (NSString* aWord in myArray) {

    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    NSString* lowerAndShorter = [[aWord lowercaseString] substringFromIndex:1];

    [myMutableArray addObject: lowerAndShorter];

    [pool release];

}

 

 

Nib Loading and Memory Management

On iOS, when a nib loads, the top-level nib objects that it instantiates are autoreleased. So if someone doesn’t retain them, they’ll eventually vanish in a puff of smoke. There are two primary strategies for preventing that from happening:

Outlet graph with retain

A memory management graph is formed: every top-level object is retained by another top-level object (without retain cycles, of course), with the File’s Owner as the start of the graph. So, the File’s Owner proxy has an outlet to a top-level object, and this outlet is backed by an accessor whose setter uses a retain policy. Thus, when the nib loads, the nib owner retains this top-level object (and must, of course, remember to release it before it itself goes out of existence). And so on, for every top-level object. This is the strategy you’ll typically use when loading a nib.

Mass retain

The call to loadNibNamed:owner:options: returns an NSArray of the nib-instantiated  objects;  retain  this  NSArray.  This  is  the  strategy  used  by UIApplicationMain when it loads the app’s main nib.

 

Objects in the nib that are not top-level objects are already part of a memory management object graph, so there’s no need for you to retain them directly. For example, if you have a top-level UIView in the nib, and it contains a UIButton, the UIButton is the UIView’s subview — and a view retains  its subviews and  takes ownership of  them. Thus, it is sufficient to manage the UIView’s memory and to let the UIView manage the UIButton.

However, if you have an outlet to this UIButton, you must be extremely careful! Recall that this outlet will be linked to its source instance at nib-loading time using KVC. This means that if you declare an ivar as an IBOutlet, with no corresponding setter, KVC will add an extra retain to the target instance as it sets the ivar directly, which can cause a memory leak. The best practice, therefore, is always to supply an accessor. An accessor with an assign policy will defend against the entire problem.

 

Mac OS X Programmer Alert

Memory management for nib-loaded instances is different on iOS than on Mac OS X. On Mac OS X, nib-loaded instances are not autoreleased, so they don’t have to be retained, and memory management is usually automatic  in any case because  the  file’s owner  is usually an NSWindowController, which takes care of these things for you. On iOS, memory management of top-level nib objects is up to you. On Mac OS X, an outlet to a non-top-level object does not cause an extra retain if there is no accessor for the corresponding ivar; on iOS, it does.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值