Some of them haven't had time to read it. Put it here first:
1. Treat the object as memory.
The status of each object instance is saved in different memory regions. Therefore, the object creation and deletion actions are equivalent to the allocation and recovery of memory occupied by the object. The Foundation-based class libraries provide an association counting mechanism (including delayed release objects) for instances through a root object "nsobject" or other classes with the same interface ). Most of the classes in the Apple class library and the subclass based on "nsobject" or the implementation classes of their interfaces can enjoy the management capability brought about by the memory counting policy.
After Apple's frameworks is released, the memory management mechanism is placed in the lifecycle of object creation and destruction (although some places are still C methods and structures ). You will find that this is actually a very interesting thing, it does not have the same method as C to directly operate the memory (malloc/free ), it is not like a language with GC (Java & Smalltalk & Ruby & python ...) automatic Memory Management. It is a mechanism for managing memory based on the autorelease mechanism, which will be discussed below. We can think of it as the middle of the above two memory management solutions, A moderate memory management solution.
2. Object holding system
(Object ownership, I Don't Know What To translate into. For the time being, I told him to hold the system. In fact, this name is literally misleading. It's okay to understand its nature, so you don't have to worry too much about what it is called. ^_^)
The following two policies for object creation and destruction are recommended for base class libraries and other class libraries:
A. if you create an object, you have the responsibility to destroy it.
B. If you want to hold an object that is not created by you, you need to "retain" it and "release" it when it is not needed.
First, the object creator is its owner, and only its owner can destroy it. Implementing this policy will make your code simpler and stronger, and you can bypass a lot of bugs caused by references to destroyed objects or memory leaks (useless objects keep relationships. You can use the "NSAID utoreleasepool" to implement a delayed release mechanism. The creator can assign the destruction responsibility to the object instance of the "NSAID utoreleasepool" (detailed principles are described below ).
3. Object Memory Allocation and initialization
Someclass * aninstance = [[someclass alloc] init];
This is a traditional method for object creation. First allocate a piece of memory and then initialize it. In addition, there is also the concept of memory zone on the operating system level. To improve the ability to locate and use memory areas, you can use the "allocwithzone:" method to try to allocate a specified area ." All stateful subclass nsobject must extend the initialization method, for example:
@ Interface cartesiancoordinate: nsobject
{
Nsnumber * abscissa;
Nsnumber * ordinate;
}
-(Cartesiancoordinate *) initwithabscissa: (nsnumber *) anabscissa
Ordinate: (nsnumber *) anordinate;
@ End
The "nsobject" also provides the "copy, mutablecopy, copywithzone, and mutablecopywithzone" method to allocate memory and duplicate attributes to copy object instances.
4. Collection of Objects
If you do not want to use another object, send the "release" message. When no one is using it, it will be automatically sent to the "dealloc" Method for recycling if there is no association. The class that holds the attribute should release all the object instances it holds in the "dealloc" method.
@ Implementation cartesiancoordinate
...
-(Void) dealloc
{
[Abscissa release];
[Ordinate release];
Return [Super dealloc];
}
@ End
5. association records of object instances
In fact, you should be able to understand that association records are a very simple task. Each object holds an associated stenographer "retain count", which is only responsible for recording the total number of associated objects. When an object is created using "init, initwith..." or other replication methods, this number is implicitly recorded as "1 ". All other objects can send a "retain" message to hold it. This method simply adds "1" to this note. Correspondingly, each "realtries" method only reduces this number by "1 ". When it is "0", this object is recycled (call its "dealloc" method ). You can also call the "retaincount" method to query this number.
-(Void) policyuseroferror: (nsstring *) errorstring
{
Nsmutablestring * alertstring = nil;
Alertstring = [[nsmutablestring alloc] initwithstring:
@ "The following error occurred:"];
[Alertstring appendstring: errorstring];
Nsunalertpanel (alertstring ...);
[Alertstring release];
Return;
}
6. Temporary objects and automatic release methods
As you can see above, you often need to create an object only once and then destroy it. In the above example, when the scope is defined, it is very simple. However, there is a problem. A temporary object cannot be returned to the caller !!! A common method in C language is to use an existing static cache or return the dynamically allocated memory. You may have thought that its caller is responsible for releasing it. This solution is different from the memory management policy we mentioned above. It has provided a more elegant solution in the Foundation architecture. The delayed release mechanism enables the creation of temporary objects to be automatically released. See the following code:
-(Void) policyuseroferror: (nsstring *) errorstring
{
Nsmutablestring * alertstring = nil;
Alertstring = [nsmutablestring stringwithstring:
@ "The following error occurred:"];
[Alertstring appendstring: errorstring];
Nsunalertpanel (alertstring ...);
Return;
}
You can see that the "alertstring" object does not call "release" after it is created, and the caller of this method does not have to worry about releasing it, because the created object is an "autoreleased" object, this object will be automatically released. An automatically released object will be automatically called the "release" method at a certain time in the future. After an automatically released object is created, if the object is not displayed as "retain", it will be automatically destroyed in a limited life cycle. If you want to specify an object to be automatically released, you can call the "autorelease" method.
Alertstring = [nsmutablestring stringwithstring:
@ "The following error occurred:"];
It is exactly the same as the following:
Alertstring =
[[[Nsmutablestring alloc] initwithstring:
@ "The following error occurred:"] autorelwing];
For example, a method similar to stringwithstring creates an automatically released instance, which can be seen everywhere in the class library.
7. automatically release the advanced version, which gives us a deeper understanding of its working principles.
Although the concept of Automatic Object release is so simple, it is necessary to know more about its working principle. Otherwise, we will still go into the memory vulnerability abyss during the development of our embedded devices.
In fact, in one of our applications, there are many "nutoreleasepool" object instances, just like their names, which are used to collect all automatically released objects. After the "autorelease" method is called, it will be added to this pool. At a certain time point in the future, it usually refers to when the "Foundation" and "appkit" apply an event loop ends, or when the "webobjects" application request is returned, or call the "release" method of the "nutoreleasepool" object. Note that there are more than one "nutoreleasepool". Why do we need multiple "nutoreleasepools" to manage the memory? Because it is very useful to recycle all automatically released objects in a code segment. In multi-threaded applications, each thread can have a stack of automatically released pools, when you create a bunch of temporary objects, and only in a short context, such as a simple loop, you do not want to in the following code, they still occupy valuable memory resources, so you can create an "nutoreleasepool" object for this short and compact local context to manage them:
-(ID) findsomething
{
Id theobject = nil;
// Whatever we're looking
NSAID utoreleasepool * localpool = [[NSAID utoreleasepool alloc] init];
// Autoreleased objects are now automatically placed in localpool.
// Loop that creates extends temporary objects
While (theobject = nil)
{
...
If ([temporaryobject matchessomecondition])
{
Theobject = [temporaryobject retain];
// We want this one
}
}
// Get rid of all those temporary objects
[Localpool release];
Return [theobject autorelease];
}
What did we do in the previous Code:
A. We have created an "nutoreleasepool" object and pressed it to the top of the memory management pool in the current context. All the automatic memory management objects under it are put into this pool.
B. We call the "retain" method of "temporaryobject" to automatically release the object so that its lifecycle exceeds the management of the local pool.
C. Release the pool and pop it out of the stack.
D. Then, we call the "autorelease" method before returning the object to the top pool of the current pool stack.
This is a bit difficult, but the principle is actually quite simple. If you can understand the above, congratulations, the level of objective-C has reached another level.
Likewise, we can see that there is a more refined code:
-(Nsarray *) findalistofthings
{
Nsmutablearray * thingarray =
[[Nsmutablearray alloc] initwithcapacity: 25];
// The list of 25 things we're re looking
NSAID utoreleasepool * outerpool = [[NSAID utoreleasepool alloc] init];
Ntutoreleasepool * innerpool = nil;
Nsarray * largeobjectarray = nil;
Id temporaryobject = nil;
Nsenumerator * arrayenumerator = nil;
// Loops that create temporary objects
While ([thingarray count]! = 25)
{
Largeobjectarray = [self fetchlotsofobjects];
// Largeobjectarray is autoreleased and contained in
// Outer autorelease pool
Arrayenumerator = [largeobjectarray objectenumerator];
// Note that the enumerator itself is a temporary object!
// It will be released by the outerpool
// Create the inner pool on each iteration. When
// A pool is created, it automatically becomes
// "TOP" pool on the current thread's stack of pools.
Innerpool = [[NSAID utoreleasepool alloc] init];
// Autoreleased objects now go into innerpool
While (temporaryobject = [arrayenumerator nextobject])
{
...
If ([temporaryobject matchessomecondition])
{
[Thingarray addobject: temporaryobject];
// Collections retain their members
}
}
// Dispose temporary objects created on this iteration;
// Note that the objects added to thingarray during this
// Iteration are also in innerpool and thus sent a release
// Message, but are not destroyed because they have been
// Retained by thingarray and so have an additional reference
// (Their retaincount> 1)
[Innerpool release];
}
[Outerpool release];
Return [thingarray autorelease];
}
All the concepts mentioned here have been completed, and there are so many memory management things 〜〜〜
If you are interested, you can discuss some instances here ~ or send me an email ~ MSN 〜