你的位置:首页 > 操作系统

[操作系统]oc内存管理机制


一直对oc内存管理机制一知半解,今天特意看了一下官方文档,聊以记之。

本人比较懒在这里直接贴官方文档啦

//************************//

Use Accessor Methods to Make Memory Management Easier

If your class has a property that is an object, you must make sure that any object that is set as the value is not deallocated while you’re using it. You must therefore claim ownership of the object when it is set. You must also make sure you then relinquish ownership of any currently-held value.

Sometimes it might seem tedious or pedantic, but if you use accessor methods consistently, the chances of having problems with memory management decrease considerably. If you are using retain and release on instance variables throughout your code, you are almost certainly doing the wrong thing.

Consider a Counter object whose count you want to set.

@interface Counter : NSObject
@property (nonatomic, retain) NSNumber *count;
@end;
The property declares two accessor methods. Typically, you should ask the compiler to synthesize the methods; however, it’s instructive to see how they might be implemented.

In the “get” accessor, you just return the synthesized instance variable, so there is no need for retain or release:

- (NSNumber *)count {
    return _count;
}
In the “set” method, if everyone else is playing by the same rules you have to assume the new count may be disposed of at any time so you have to take ownership of the object—by sending it a retain message—to ensure it won’t be. You must also relinquish ownership of the old count object here by sending it a release message. (Sending a message to nil is allowed in Objective-C, so the implementation will still work if _count hasn’t yet been set.) You must send this after [newCount retain] in case the two are the same object—you don’t want to inadvertently cause it to be deallocated.

- (void)setCount:(NSNumber *)newCount {
    [newCount retain];
    [_count release];
    // Make the new assignment.
    _count = newCount;
}

/************************************************/

简单说就是@{get,set}方法,get方法就不说了,说说set方法

- (void)setCount:(NSNumber *)newCount {
    [newCount retain];   //newCount 引用计数+1
    [_count release];    //把_count 指针所指向的对象引用计数-1  ,没有加这句会造成内存泄露
    // Make the new assignment.
    _count = newCount; //单纯的指针赋值
}

 

/***************************************/

The second uses a convenience constructor to create a new NSNumber object. There is therefore no need for retain or release messages

- (void)reset {
    NSNumber *zero = [NSNumber numberWithInteger:0];
    [self setCount:zero];
}
Note that both use the set accessor method.

The following will almost certainly work correctly for simple cases, but as tempting as it may be to eschew accessor methods, doing so will almost certainly lead to a mistake at some stage (for example, when you forget to retain or release, or if the memory management semantics for the instance variable change).

- (void)reset {
    NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
    [_count release];
    _count = zero;
}
Note also that if you are using key-value observing, then changing the variable in this way is not KVO compliant.

/**********************************************************/

这是官方写的一个reset 方法,简单的说 alloc  出来的对象引用计数+1,所以在不需要的时候需要 release,

[NSNumber numberWithInteger:0];  这种方法引用计数没有+1 ,因此再不需要的时候 ,也不需要release,

至于内部是如何实现,本文就不做研究了。

/************************************************************/

 

Don’t Use Accessor Methods in Initializer Methods and dealloc
The only places you shouldn’t use accessor methods to set an instance variable are in initializer methods and dealloc. To initialize a counter object with a number object representing zero, you might implement an init method as follows:

- init {
    self = [super init];
    if (self) {
        _count = [[NSNumber alloc] initWithInteger:0];
    }
    return self;
}

/************************************************************/

这个比较重要 ,类的初始化方法 中,不能实现类似 self.count 这样的方法,这是因为 类似self.count =1;

个人理解是这样的  init() 方法只有在返回的时候该类才能说被完整的创建。

self.count 相当于 self.getcount();方法 由于 这个方法很有可能被重载了,而导致结果难以预料。  //*注 :如有错误欢迎指正

不管如何这个都应该成为我们的设计准则。

/************************************************************/

Use Weak References to Avoid Retain Cycles

Retaining an object creates a strong reference to that object. An object cannot be deallocated until all of its strong references are released. A problem, known as a retain cycle, can therefore arise if two objects may have cyclical references—that is, they have a strong reference to each other (either directly, or through a chain of other objects each with a strong reference to the next leading back to the first).

The object relationships shown in Figure 1 illustrate a potential retain cycle. The Document object has a Page object for each page in the document. Each Page object has a property that keeps track of which document it is in. If the Document object has a strong reference to the Page object and the Page object has a strong reference to the Document object, neither object can ever be deallocated. The Document’s reference count cannot become zero until the Page object is released, and the Page object won’t be released until the Document object is deallocated.

The solution to the problem of retain cycles is to use weak references. A weak reference is a non-owning relationship where the source object does not retain the object to which it has a reference.

To keep the object graph intact, however, there must be strong references somewhere (if there were only weak references, then the pages and paragraphs might not have any owners and so would be deallocated). Cocoa establishes a convention, therefore, that a “parent” object should maintain strong references to its “children,” and that the children should have weak references to their parents.

So, in Figure 1 the document object has a strong reference to (retains) its page objects, but the page object has a weak reference to (does not retain) the document object.

Examples of weak references in Cocoa include, but are not restricted to, table data sources, outline view items, notification observers, and miscellaneous targets and delegates.

You need to be careful about sending messages to objects for which you hold only a weak reference. If you send a message to an object after it has been deallocated, your application will crash. You must have well-defined conditions for when the object is valid. In most cases, the weak-referenced object is aware of the other object’s weak reference to it, as is the case for circular references, and is responsible for notifying the other object when it deallocates. For example, when you register an object with a notification center, the notification center stores a weak reference to the object and sends messages to it when the appropriate notifications are posted. When the object is deallocated, you need to unregister it with the notification center to prevent the notification center from sending any further messages to the object, which no longer exists. Likewise, when a delegate object is deallocated, you need to remove the delegate link by sending a setDelegate: message with a nil argument to the other object. These messages are normally sent from the object’s dealloc method.

/************************************************************/

简单的解释下 ,想必大家都对retain,assign,weak,strong这些有所理解,但是什么时候使用什么引用呢?

首先官方文档说明了一种情况 ,就是在 A 引用 B ,B引用C的情况下,这样就形成了一个闭环,造成内存无法被释放掉,这个时候怎么办?

官方的解决方法是采用 weak和strong 来解决它,只有根部的属性采用strong 描述,weak 用于描述子的属性,这样就能解决循环引用问题。 简单的说 strong 属性会令引用计数+1,而weak则不会,这样就不会造成循环引用。

/**************************************************************/

Ownership Policy Is Implemented Using Retain Counts

The ownership policy is implemented through reference counting—typically called “retain count” after the retain method. Each object has a retain count.

When you create an object, it has a retain count of 1.
When you send an object a retain message, its retain count is incremented by 1.
When you send an object a release message, its retain count is decremented by 1.
When you send an object a autorelease message, its retain count is decremented by 1 at the end of the current autorelease pool block.

If an object’s retain count is reduced to zero, it is deallocated.

Important: There should be no reason to explicitly ask an object what its retain count is (see retainCount). The result is often misleading, as you may be unaware of what framework objects have retained an object in which you are interested. In debugging memory management issues, you should be concerned only with ensuring that your code adheres to the ownership rules.

/**************************************************************/

这是引用计数设计的几条原则,苹果特意说明了只需要遵守这几个准则就行了,任何试图打印当前引用计数的方法,所得到的结果都可能是错误的。

其他的还有一些细节,就不再这里一一赘述了。

总结一下 :引用计数分为3类:

1.assign 

2.copy

3. retain  (其中包含 weak和strong 用于解决循环引用问题)