|  | // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef BASE_MAC_OBJC_PROPERTY_RELEASER_H_ | 
|  | #define BASE_MAC_OBJC_PROPERTY_RELEASER_H_ | 
|  |  | 
|  | #import <Foundation/Foundation.h> | 
|  |  | 
|  | #include "base/base_export.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace mac { | 
|  |  | 
|  | // ObjCPropertyReleaser is a C++ class that can automatically release | 
|  | // synthesized Objective-C properties marked "retain" or "copy". The expected | 
|  | // use is to place an ObjCPropertyReleaser object within an Objective-C class | 
|  | // definition. When built with the -fobjc-call-cxx-cdtors compiler option, | 
|  | // the ObjCPropertyReleaser's destructor will be called when the Objective-C | 
|  | // object that owns it is deallocated, and it will send a -release message to | 
|  | // the instance variables backing the appropriate properties. If | 
|  | // -fobjc-call-cxx-cdtors is not in use, ObjCPropertyReleaser's | 
|  | // ReleaseProperties method can be called from -dealloc to achieve the same | 
|  | // effect. | 
|  | // | 
|  | // Example usage: | 
|  | // | 
|  | // @interface AllaysIBF : NSObject { | 
|  | //  @private | 
|  | //   NSString* string_; | 
|  | //   NSMutableDictionary* dictionary_; | 
|  | //   NSString* notAProperty_; | 
|  | //   IBFDelegate* delegate_;  // weak | 
|  | // | 
|  | //   // It's recommended to put the class name into the property releaser's | 
|  | //   // instance variable name to gracefully handle subclassing, where | 
|  | //   // multiple classes in a hierarchy might want their own property | 
|  | //   // releasers. | 
|  | //   base::mac::ObjCPropertyReleaser propertyReleaser_AllaysIBF_; | 
|  | // } | 
|  | // | 
|  | // @property(retain, nonatomic) NSString* string; | 
|  | // @property(copy, nonatomic) NSMutableDictionary* dictionary; | 
|  | // @property(assign, nonatomic) IBFDelegate* delegate; | 
|  | // @property(retain, nonatomic) NSString* autoProp; | 
|  | // | 
|  | // @end  // @interface AllaysIBF | 
|  | // | 
|  | // @implementation AllaysIBF | 
|  | // | 
|  | // @synthesize string = string_; | 
|  | // @synthesize dictionary = dictionary_; | 
|  | // @synthesize delegate = delegate_; | 
|  | // @synthesize autoProp; | 
|  | // | 
|  | // - (id)init { | 
|  | //   if ((self = [super init])) { | 
|  | //     // Initialize with [AllaysIBF class]. Never use [self class] because | 
|  | //     // in the case of subclassing, it will return the most specific class | 
|  | //     // for |self|, which may not be the same as [AllaysIBF class]. This | 
|  | //     // would cause AllaysIBF's -.cxx_destruct or -dealloc to release | 
|  | //     // instance variables that only exist in subclasses, likely causing | 
|  | //     // mass disaster. | 
|  | //     propertyReleaser_AllaysIBF_.Init(self, [AllaysIBF class]); | 
|  | //   } | 
|  | //   return self; | 
|  | // } | 
|  | // | 
|  | // @end  // @implementation AllaysIBF | 
|  | // | 
|  | // When an instance of AllaysIBF is deallocated, the ObjCPropertyReleaser will | 
|  | // send a -release message to string_, dictionary_, and the compiler-created | 
|  | // autoProp instance variables. No -release will be sent to delegate_ as it | 
|  | // is marked "assign" and not "retain" or "copy". No -release will be sent to | 
|  | // notAProperty_ because it doesn't correspond to any declared @property. | 
|  | // | 
|  | // Another way of doing this would be to provide a base class that others can | 
|  | // inherit from, and to have the base class' -dealloc walk the property lists | 
|  | // of all subclasses in an object to send the -release messages. Since this | 
|  | // involves a base reaching into its subclasses, it's deemed scary, so don't | 
|  | // do it. ObjCPropertyReleaser's design ensures that the property releaser | 
|  | // will only operate on instance variables in the immediate object in which | 
|  | // the property releaser is placed. | 
|  |  | 
|  | class BASE_EXPORT ObjCPropertyReleaser { | 
|  | public: | 
|  | // ObjCPropertyReleaser can only be owned by an Objective-C object, so its | 
|  | // memory is always guaranteed to be 0-initialized. Not defining the default | 
|  | // constructor can prevent an otherwise no-op -.cxx_construct method from | 
|  | // showing up in Objective-C classes that contain a ObjCPropertyReleaser. | 
|  |  | 
|  | // Upon destruction (expected to occur from an Objective-C object's | 
|  | // -.cxx_destruct method), release all properties. | 
|  | ~ObjCPropertyReleaser() { | 
|  | ReleaseProperties(); | 
|  | } | 
|  |  | 
|  | // Initialize this object so that it's armed to release the properties of | 
|  | // object |object|, which must be of type |classy|. The class argument must | 
|  | // be supplied separately and cannot be gleaned from the object's own type | 
|  | // because an object will allays identify itself as the most-specific type | 
|  | // that describes it, but the ObjCPropertyReleaser needs to know which class | 
|  | // type in the class hierarchy it's responsible for releasing properties | 
|  | // for. For the same reason, Init must be called with a |classy| argument | 
|  | // initialized using a +class (class) method such as [MyClass class], and | 
|  | // never a -class (instance) method such as [self class]. | 
|  | // | 
|  | // -.cxx_construct can only call the default constructor, but | 
|  | // ObjCPropertyReleaser needs to know about the Objective-C object that owns | 
|  | // it, so this can't be handled in a constructor, it needs to be a distinct | 
|  | // Init method. | 
|  | void Init(id object, Class classy); | 
|  |  | 
|  | // Release all of the properties in object_ defined in class_ as either | 
|  | // "retain" or "copy" and with an identifiable backing instance variable. | 
|  | // Properties must be synthesized to have identifiable instance variables. | 
|  | void ReleaseProperties(); | 
|  |  | 
|  | private: | 
|  | id object_; | 
|  | Class class_; | 
|  | }; | 
|  |  | 
|  | }  // namespace mac | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_MAC_OBJC_PROPERTY_RELEASER_H_ |