// 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_