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_ 7 8 #import <Foundation/Foundation.h> 9 10 #include "base/base_export.h" 11 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 85 class BASE_EXPORT ObjCPropertyReleaser { 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_ 128