Home | History | Annotate | Download | only in mac
      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