Recently I was working on a game engine, cocos2d, and thus had some experience to share with you guys. As an objective c beginner, I found it’s hard to understand the basic concept of objective c memory strategy especially when I have experience of using C/C++ before. Hope this article help you!
In general, there are three types of memory management in Objective C. First one is Manual Retain Release (MRR), second one is Automatic Reference Count (ARC) and the last one is automatic garbage collection. Since cocos2d v2.0 and before versions don’t support ARC and garbage collection is not available in iOS devices, there is only MRR left for us to use.
The memory management in iOS development is based on the idea of ownership, that is to say, the ones who own the object are responsible for releasing it; others do not and should not. Please refer to the illustration below.
Through the ownership model, memory management becomes easier if you obey several basic rules.
1. When a pointer owns an object, you should release the object when destroying the pointer.
2. When a pointer does not own the referenced object, you should not release this object in any case.
3. Pointer should not take the ownership if this pointer should not owns the object in a logical sense. For example, subclass object should not own its parent object.
This model converts programmers from thinking from a memory view to an object ownership view. Usually, an object of subclass should not retain its parent.
By obeying those basic rules, developer can easily manage their memory without worrying about dangling pointer and NULL pointer. These bad pointers are common in C/C++ programs. In C/C++, every pointer can be the owner and can release the referenced object. (Actually, in Obj-C, every pointer can still release the memory it’s pointing to like it is in C/C++, however, to maintain the ownership model, it is highly suggested that only pointers owning the memory do the release action. This is not compulsory, however, it is one of the best practices in Obj-C programming.)
Yet there are some drawbacks when applying ownership model. If you are not cautious enough, retain circle is a typical example. Here is some practices you should read to avoid retain circle.
Moreover, when talking about ownership model in objective C, I have to mention autorelease pool.
Let’s consider a complex situation, you allocate and initialize an object in a method, and then you want to return this object to the caller, like the below code shows:
However, due to the ownership model, we know that local variable foo holds the ownership of this object, and the returned pointer also owns it. This undermines our ownership concept. Since pointer foo will be destroyed after returning function and foo owns this part of memory, we should release this part of memory before destroying pointer foo. Yet if it releases the object before the returning, the object will be deallocated. So how to handle this paradox in ownership model?
If this is in C/C++, we do not have method retain. Releasing a pointer will definitely release the memory it points to, we won’t have this kind of issue.
Autorelease pool is aiming at solving this kind of problem. Please refer to the below improved code first:
After initializing the object, I call autorelease method. This autorelease method will put the object into an autorelease pool. Yet unlike release method, this object will not be deallocated immediately, you can still use it through any pointers pointing to. System later will send a release message to each of the object in autorelease pool when autorelease pool is deallocated. This mechanism solves this kind of problem. Because of this mechanism, there are three types of properties of variable. Those are assign, retain and copy. If you want to have a deeper understanding of this, please refer to this article. Actually, this kind of understanding is important if you want your program looks tidy. 🙂
In cocos2d, it’s normal to get an object by calling a class’ static method, e.g. (getting a node by calling [CCNode node], getting a sprite through calling [CCSprite spriteWithFile]).
Let’s take a close look at the implementation of these static method.
You should be cautious because that these objects returned from static method has been put into autorelease pool. That means you have to decide carefully who should own these objects. Usually we will add them into the children array of their parent node, which increase their reference when putting into an array. However, it’s easy to forget to retain the object if you let a member variable to hold the reference and do not add it as a child. (I don’t know whether you will, I always forget to retain it. )
Actually, ownership model is a new way of thinking memory management especially when you used to be a C/C++ programmer. When writing C/C++ code, we are often tangled with dangling or NULL pointers, so we have to elaborately design a memory model. Compared with C/C++ code, Objective C takes advantages of ownership model. It releases us from low-level memory allocation and encourages us to think about the logic ownership, which usually improves the readability and maintenance of our code.
(WARNING: ownership model is not compulsory, still you may use your old way in C/C++ to manage memory, yet since objective c introduces reference count mechanism, it’s better to program with an ownership model in your heart. This is a best practice if you want your code to be easy-maintain and easily readable.) 🙂