[email protected] | 10756c5 | 2011-04-20 22:30:35 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef BASE_MAC_OBJC_PROPERTY_RELEASER_H_ |
| 6 | #define BASE_MAC_OBJC_PROPERTY_RELEASER_H_ |
[email protected] | 10756c5 | 2011-04-20 22:30:35 | [diff] [blame] | 7 | |
| 8 | #import <Foundation/Foundation.h> |
| 9 | |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 10 | #include "base/base_export.h" |
[email protected] | 8ca8772 | 2011-07-29 04:43:14 | [diff] [blame] | 11 | |
[email protected] | 10756c5 | 2011-04-20 22:30:35 | [diff] [blame] | 12 | namespace base { |
| 13 | namespace mac { |
| 14 | |
| 15 | // ObjCPropertyReleaser is a C++ class that can automatically release |
| 16 | // synthesized Objective-C properties marked "retain" or "copy". The expected |
| 17 | // use is to place an ObjCPropertyReleaser object within an Objective-C class |
| 18 | // definition. When built with the -fobjc-call-cxx-cdtors compiler option, |
| 19 | // the ObjCPropertyReleaser's destructor will be called when the Objective-C |
| 20 | // object that owns it is deallocated, and it will send a -release message to |
| 21 | // the instance variables backing the appropriate properties. If |
| 22 | // -fobjc-call-cxx-cdtors is not in use, ObjCPropertyReleaser's |
| 23 | // ReleaseProperties method can be called from -dealloc to achieve the same |
| 24 | // effect. |
| 25 | // |
| 26 | // Example usage: |
| 27 | // |
| 28 | // @interface AllaysIBF : NSObject { |
| 29 | // @private |
| 30 | // NSString* string_; |
| 31 | // NSMutableDictionary* dictionary_; |
| 32 | // NSString* notAProperty_; |
| 33 | // IBFDelegate* delegate_; // weak |
| 34 | // |
| 35 | // // It's recommended to put the class name into the property releaser's |
| 36 | // // instance variable name to gracefully handle subclassing, where |
| 37 | // // multiple classes in a hierarchy might want their own property |
| 38 | // // releasers. |
| 39 | // base::mac::ObjCPropertyReleaser propertyReleaser_AllaysIBF_; |
| 40 | // } |
| 41 | // |
| 42 | // @property(retain, nonatomic) NSString* string; |
| 43 | // @property(copy, nonatomic) NSMutableDictionary* dictionary; |
| 44 | // @property(assign, nonatomic) IBFDelegate* delegate; |
| 45 | // @property(retain, nonatomic) NSString* autoProp; |
| 46 | // |
| 47 | // @end // @interface AllaysIBF |
| 48 | // |
| 49 | // @implementation AllaysIBF |
| 50 | // |
| 51 | // @synthesize string = string_; |
| 52 | // @synthesize dictionary = dictionary_; |
| 53 | // @synthesize delegate = delegate_; |
| 54 | // @synthesize autoProp; |
| 55 | // |
| 56 | // - (id)init { |
| 57 | // if ((self = [super init])) { |
| 58 | // // Initialize with [AllaysIBF class]. Never use [self class] because |
| 59 | // // in the case of subclassing, it will return the most specific class |
| 60 | // // for |self|, which may not be the same as [AllaysIBF class]. This |
| 61 | // // would cause AllaysIBF's -.cxx_destruct or -dealloc to release |
| 62 | // // instance variables that only exist in subclasses, likely causing |
| 63 | // // mass disaster. |
| 64 | // propertyReleaser_AllaysIBF_.Init(self, [AllaysIBF class]); |
| 65 | // } |
| 66 | // return self; |
| 67 | // } |
| 68 | // |
| 69 | // @end // @implementation AllaysIBF |
| 70 | // |
| 71 | // When an instance of AllaysIBF is deallocated, the ObjCPropertyReleaser will |
| 72 | // send a -release message to string_, dictionary_, and the compiler-created |
| 73 | // autoProp instance variables. No -release will be sent to delegate_ as it |
| 74 | // is marked "assign" and not "retain" or "copy". No -release will be sent to |
| 75 | // notAProperty_ because it doesn't correspond to any declared @property. |
| 76 | // |
| 77 | // Another way of doing this would be to provide a base class that others can |
| 78 | // inherit from, and to have the base class' -dealloc walk the property lists |
| 79 | // of all subclasses in an object to send the -release messages. Since this |
| 80 | // involves a base reaching into its subclasses, it's deemed scary, so don't |
| 81 | // do it. ObjCPropertyReleaser's design ensures that the property releaser |
| 82 | // will only operate on instance variables in the immediate object in which |
| 83 | // the property releaser is placed. |
| 84 | |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 85 | class BASE_EXPORT ObjCPropertyReleaser { |
[email protected] | 10756c5 | 2011-04-20 22:30:35 | [diff] [blame] | 86 | public: |
| 87 | // ObjCPropertyReleaser can only be owned by an Objective-C object, so its |
| 88 | // memory is always guaranteed to be 0-initialized. Not defining the default |
| 89 | // constructor can prevent an otherwise no-op -.cxx_construct method from |
| 90 | // showing up in Objective-C classes that contain a ObjCPropertyReleaser. |
| 91 | |
| 92 | // Upon destruction (expected to occur from an Objective-C object's |
| 93 | // -.cxx_destruct method), release all properties. |
| 94 | ~ObjCPropertyReleaser() { |
| 95 | ReleaseProperties(); |
| 96 | } |
| 97 | |
| 98 | // Initialize this object so that it's armed to release the properties of |
| 99 | // object |object|, which must be of type |classy|. The class argument must |
| 100 | // be supplied separately and cannot be gleaned from the object's own type |
| 101 | // because an object will allays identify itself as the most-specific type |
| 102 | // that describes it, but the ObjCPropertyReleaser needs to know which class |
| 103 | // type in the class hierarchy it's responsible for releasing properties |
| 104 | // for. For the same reason, Init must be called with a |classy| argument |
| 105 | // initialized using a +class (class) method such as [MyClass class], and |
| 106 | // never a -class (instance) method such as [self class]. |
| 107 | // |
| 108 | // -.cxx_construct can only call the default constructor, but |
| 109 | // ObjCPropertyReleaser needs to know about the Objective-C object that owns |
| 110 | // it, so this can't be handled in a constructor, it needs to be a distinct |
| 111 | // Init method. |
| 112 | void Init(id object, Class classy); |
| 113 | |
| 114 | // Release all of the properties in object_ defined in class_ as either |
| 115 | // "retain" or "copy" and with an identifiable backing instance variable. |
| 116 | // Properties must be synthesized to have identifiable instance variables. |
| 117 | void ReleaseProperties(); |
| 118 | |
| 119 | private: |
| 120 | id object_; |
| 121 | Class class_; |
| 122 | }; |
| 123 | |
| 124 | } // namespace mac |
| 125 | } // namespace base |
| 126 | |
| 127 | #endif // BASE_MAC_OBJC_PROPERTY_RELEASER_H_ |