Effective Objective-C 2.0: Item 31: Release References and Clean Up Observation State Only in deallo
2013-12-09 09:41
871 查看
Item 31: Release References and Clean Up Observation State Only in dealloc
An object going through its life cycle eventually ends up being deallocated, which is where the deallocmethod
enters. It is called exactly once during the life cycle of an object: when its retain count drops to zero. When exactly it gets called is not guaranteed, though. Also, you may think that you know when it’s going to be called from manually seeing where retains
and releases are. But in practice, any library could be manipulating the object without your knowing, causing deallocation to happen at another time. You should never call
deallocyourself.
The runtime will call it at exactly the right time for you. Also, after
deallochas been called on an object, that object is no longer valid, and subsequent method calls
are invalid.
So what should you do in
deallocthen? The main thing to do is to release any references that the object owns. This means releasing any Objective-C
objects, something that ARC automatically adds for you into the
deallocmethod, through the
.cxx_destructautomatic method (see Item
30). Any other non-Objective-C objects that the object owns also need releasing. For instance, CoreFoundation objects need to be explicitly released, since they are pure C APIs.
Another usual thing to do in a
deallocmethod
is to clean up any observation behavior that has been set up. If
NSNotificationCenterhas
been used to register the object for certain notifications, this is often a good place to unregister for notifications so that they are not attempted to be sent to a deallocated object, which would certainly cause an application to crash.
A
deallocmethod looks like this:
Click here to view code image
- (void)dealloc {
CFRelease(coreFoundationObject);
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Note that when using manual reference counting rather than ARC,
[super dealloc]should be the last thing done. ARC automatically enforces this, which is another reason why it is a lot easier
and safer to use than manual reference counting. With manual reference counting, this method would also have to manually release every Objective-C object owned by the object.
That said, you should certainly not free resources that are potentially expensive or scarce within the system. Such resources are file descriptors, sockets, or large blocks of memory. The
deallocmethod should
not be relied on to be called at any specific time, since something you hadn’t realized might be holding onto the object. In such a situation, you are keeping hold of scarce system resources longer than you need to, which is undesirable. It
is usual in these scenarios to implement another method that should be called when the application has finished with the object. The resources’ life cycles are then made deterministic.
An example of an object that might need a cleanup method is one that manages a socket connection to a server. Perhaps it is a connection to a database. Such a class’s interface may look like
this:
Click here to view code image
#import <Foundation/Foundation.h>
@interface EOCServerConnection : NSObject
- (void)open:(NSString*)address;
- (void)close;
@end
The contract for this class would be that the
open:method is called to open the connection; then,
when finished with the connection, the application calls
close. The close must happen before the connection object is deallocated; otherwise, it is deemed to be a programmer
error, just as you have to balance retains and releases with reference counting.
Another reason for cleaning up resources in another cleanup method is that the
deallocmethod
is in fact not guaranteed to be run for every created object. There is the edge case of objects that are still around when an application terminates. These objects do not receive the
deallocmessage.
Instead, they are destroyed by the fact that a terminated application’s resources are returned to the operating system. It is an optimization not to call the
deallocmethod.
But this means that you cannot guarantee that it is always called for every object. Mac OS X and iOS applications both have within their application delegates a method that is called on application termination. This
method can be used to run any cleanup methods on objects that need to be guaranteed to be cleaned up.
In the case of Mac OS X, the method called at application termination is on
NSApplicationDelegate:
- (void)applicationWillTerminate:(NSNotification *)notification
In the case of iOS, the method is on
UIApplicationDelegate:
- (void)applicationWillTerminate:(UIApplication *)application
With regard to the cleanup method for objects that manage resources, this should also be called in
deallocto
mitigate the case in which the cleanup method was not called. If this does happen, it is often a good idea to output a log line to indicate that a programmer error has occurred. It is a programmer error because
closeshould
have been called before the object was deallocated; otherwise, the
closemethod is irrelevant. This log line will alert the programmer to rectify the problem. It’s still
good practice to close the resources in
deallocin order to avoid leaks. An example of such a
closeand
deallocmethod
is as follows:
Click here to view code image
- (void)close {
/* clean up resources */
_closed = YES;
}
- (void)dealloc {
if (!_closed) {
NSLog(@"ERROR: close was not called before dealloc!");
[self close];
}
}
Instead of simply logging an error if the
closemethod is not called, you might decide to throw an exception
to indicate that a serious programmer error has occurred.
Another thing to be aware of and avoid in
deallocmethods is calling other methods. In the preceding example, of course, a method is called in
dealloc.
But this is a special case: to detect programmer error. It is not ideal to have to call any other methods at all, because the object being deallocated is in a winding-down state. If the other method happens to perform work asynchronously or calls methods that
themselves do, the object being deallocated could be completely dead by the time those methods finish doing their work. This can cause all sorts of problems and often results in an application crash because it calls back to tell the object that it has finished.
If the object is dead, this call will fail.
Also, the
deallocmethod is called on the thread in which the final release that caused the retain count to zero occurred. Some methods are
required to be run in a certain thread, such as the main thread. If these methods are called from
dealloc,there is no safe way to ensure that it is run on the correct
thread. Any usual code to force it to be run on the correct thread is not at all safe, because the object is in a deallocating state, and the runtime has already started altering
its internal data structures to indicate this.
The avoidance of method calls in
deallocshould also go for property accessors, which can be overridden and therefore themselves try to perform
work that is unsafe to do during deallocation. Alternatively, the property may be being observed through Key-Value Observation (KVO), and the observer may try to do some work, such as attempting to retain the object, using the object that is being deallocated.
Doing so would cause the runtime to get in a completely inconsistent state, and strange crashes would likely result.
Things to Remember
The
deallocmethod
should be used only to release references to other objects and to unregister anything that needs to be, such as Key-Value Observing (KVO) or
NSNotificationCenternotifications.
If
an object holds onto system resources, such as file descriptors, there should be a method for releasing these resources. It should be the contract with the consumer of such a class to call this
closemethod
when finished using the resources.
Method
calls should be avoided in
deallocmethods
in case those methods try to perform asynchronous work or end up assuming that the object is in a normal state, which it won’t be.
相关文章推荐
- Item 15: Utilize using and try/finally for Resource Cleanup(Effective C#)
- Working copy XXX locked and cleanup failed in SVN
- Constructor and destructor -- Initialization & Cleanup in C++
- Item 15:Utilize using and try/finally for Resource Cleanup
- Effective C# Item 15: Utilize using and try/finally for Resource Cleanup
- Speed Up Your Site with the Improved View State in ASP.NET 2.0
- How To Automate Cleanup Of Dead Connections And INACTIVE 【如何自动清理ORACLE中的死连接和非活动会话】
- How To Automate Cleanup Of Dead Connections And INACTIVE Sessions [ID 206007.1]
- .NET错误The 'targetFramework' attribute in the <compilation> element of the Web.config file is used only to target version 4.0 and later of the .NET Framework
- Add Ribbon button and menu item in Sharepoint 2010
- How To Turn Up Logging on the Siebel Web Server Extension in Siebel Versions 7.x and 8.x? [ID 477185
- Only Link: Inheritance — private and protected inheritance in c++
- php中出现Strict Standards: Only variables should be passed by reference in的解决方法
- How to Create a Slick and Clean Button in Photoshop
- IOS 深入学习(31)之About Drawing and Printing in iOS(绘图和打印)
- Proxy and State in Python
- Calling latest() can only be used in combination with key(String) and keyLike(String)
- Could not find a price list in Ordered UOM xxx and Primary UOM of the item
- 关于NSAutoreleasePool' is unavailable: not available in automatic reference counting mode的解决方法 .
- Using commands with ApplicationBarMenuItem and ApplicationBarButton in Windows Phone 7