]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/cocoa/ObjcRef.h
simplify wxEVT_MENU_OPEN/CLOSE generation
[wxWidgets.git] / include / wx / cocoa / ObjcRef.h
index 2af1c2598a16715c39bb1d3c5cc3de9faccd7819..ccb3d3156f685f77fddb5c61fecaf2783f0ef3eb 100644 (file)
@@ -9,6 +9,109 @@
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
+#ifndef _WX_COCOA_OBJCREF_H__
+#define _WX_COCOA_OBJCREF_H__
+
+// Reuse wxCFRef-related code (e.g. wxCFRetain/wxCFRelease)
+#include "wx/mac/corefoundation/cfref.h"
+
+// NOTE WELL: We can only know whether or not GC can be used when compiling Objective-C.
+// Therefore we cannot implement these functions except when compiling Objective-C.
+#ifdef __OBJC__
+/*! @function   wxGCSafeRetain
+    @templatefield  Type    (implicit) An Objective-C class type
+    @arg            r       Pointer to Objective-C object.  May be null.
+    @abstract   Retains the Objective-C object, even when using Apple's garbage collector
+    @discussion
+    When Apple's garbage collector is enabled, the usual [obj retain] and [obj release] messages
+    are ignored.  Instead the collector with help from compiler-generated write-barriers tracks
+    reachable objects.  The write-barriers are generated when setting i-vars of C++ classes but
+    they are ignored by the garbage collector unless the C++ object is in GC-managed memory.
+
+    The simple solution is to use CFRetain on the Objective-C object which has been enhanced in
+    GC mode to forcibly retain the object.  In Retain/Release (RR) mode the CFRetain function has
+    the same effect as [obj retain].  Note that GC vs. RR is selected at runtime.
+
+    Take care that wxGCSafeRetain must be balanced with wxGCSafeRelease and that conversely
+    wxGCSafeRelease must only be called on objects to balance wxGCSafeRetain.  In particular when
+    receiving an Objective-C object from an alloc or copy method take care that you must retain
+    it with wxGCSafeRetain and balance the initial alloc with a standard release.
+
+    Example:
+    wxGCSafeRelease(m_obj); // release current object (if any)
+    NSObject *obj = [[NSObject alloc] init];
+    m_obj = wxGCSafeRetain(obj);
+    [obj release];
+
+    Alternatively (same effect, perhaps less clear):
+    wxGCSafeRelease(m_obj); // release current object (if any)
+    m_obj = wxGCSafeRetain([[NSObject alloc] init]);
+    [m_obj release]; // balance alloc
+    
+    Consider the effect on the retain count from each statement (alloc, CFRetain, release)
+    In RR mode:     retainCount = 1, +1, -1
+    In GC mode:     strongRetainCount = 0, +1, -0
+
+    This is a template function to ensure it is used on raw pointers and never on pointer-holder
+    objects via implicit conversion operators.
+*/
+template <class Type>
+inline Type * wxGCSafeRetain(Type *r)
+{
+#ifdef __OBJC_GC__
+    return static_cast<Type*>(wxCFRetain(r));
+#else
+    return [r retain];
+#endif
+}
+
+/*! @function   wxGCSafeRelease
+    @templatefield  Type    (implicit) An Objective-C class type
+    @arg            r       Pointer to Objective-C object.  May be null.
+    @abstract   Balances wxGCSafeRetain.  Particularly useful with the Apple Garbage Collector.
+    @discussion
+    See the wxGCSafeRetain documentation for more details.
+
+    Example (from wxGCSafeRetain documentation):
+    wxGCSafeRelease(m_obj); // release current object (if any)
+    m_obj = wxGCSafeRetain([[NSObject alloc] init]);
+    [m_obj release]; // balance alloc
+
+    When viewed from the start, m_obj ought to start as nil. However, the second time through
+    the wxGCSafeRelease call becomes critical as it releases the retain from the first time
+    through.
+
+    In the destructor for this C++ object with the m_obj i-var you ought to do the following:
+    wxGCSafeRelease(m_obj);
+    m_obj = nil; // Not strictly needed, but safer.
+
+    Under no circumstances should you balance an alloc or copy with a wxGCSafeRelease.
+*/
+template <class Type>
+inline void wxGCSafeRelease(Type *r)
+{
+#ifdef __OBJC_GC__
+    wxCFRelease(r);
+#else
+    [r release];
+#endif
+}
+#else
+// NOTE: When not compiling Objective-C, declare these functions such that they can be
+// used by other inline-implemented methods.  Since those methods in turn will not actually
+// be used from non-ObjC code the compiler ought not emit them.  If it emits an out of
+// line copy of those methods then presumably it will have also emitted at least one
+// out of line copy of these functions from at least one Objective-C++ translation unit.
+// That means the out of line implementation will be available at link time.
+
+template <class Type>
+inline Type * wxGCSafeRetain(Type *r);
+
+template <class Type>
+inline void wxGCSafeRelease(Type *r);
+
+#endif //def __OBJC__
+
 /*
 wxObjcAutoRefFromAlloc: construct a reference to an object that was
 [NSObject -alloc]'ed and thus does not need a retain
@@ -22,12 +125,32 @@ struct objc_object;
 class wxObjcAutoRefBase
 {
 protected:
+    /*! @function   ObjcRetain
+        @abstract   Simply does [p retain].
+     */
     static struct objc_object* ObjcRetain(struct objc_object*);
-    static struct objc_object* ObjcRelease(struct objc_object*);
+
+    /*! @function   ObjcRelease
+        @abstract   Simply does [p release].
+     */
+    static void ObjcRelease(struct objc_object*);
 };
 
-// T should be a pointer like NSObject*
+/*! @class      wxObjcAutoRefFromAlloc
+    @templatefield  T       The type of _pointer_ (e.g. NSString*, NSRunLoop*)
+    @abstract   Pointer-holder for Objective-C objects
+    @discussion
+    When constructing this object from a raw pointer, the pointer is assumed to have
+    come from an alloc-style method.  That is, once you construct this object from
+    the pointer you must not balance your alloc with a call to release.
 
+    This class has been carefully designed to work with both the traditional Retain/Release
+    and the new Garbage Collected modes.  In RR-mode it will prevent the object from being
+    released by managing the reference count using the retain/release semantics.  In GC-mode
+    it will use a method (currently CFRetain/CFRelease) to ensure the object will never be
+    finalized until this object is destroyed.
+ */
+    
 template <class T>
 class wxObjcAutoRefFromAlloc: wxObjcAutoRefBase
 {
@@ -35,34 +158,70 @@ public:
     wxObjcAutoRefFromAlloc(T p = 0)
     :   m_ptr(p)
     // NOTE: this is from alloc.  Do NOT retain
-    {}
+    {
+        //  CFRetain
+        //      GC:     Object is strongly retained and prevented from being collected
+        //      non-GC: Simply realizes it's an Objective-C object and calls [p retain]
+        wxGCSafeRetain(p);
+        //  ObjcRelease (e.g. [p release])
+        //      GC:     Objective-C retain/release mean nothing in GC mode
+        //      non-GC: This is a normal release call, balancing the retain
+        ObjcRelease(static_cast<T>(p));
+        //  The overall result:
+        //      GC:     Object is strongly retained
+        //      non-GC: Retain count is the same as it was (retain then release)
+    }
     wxObjcAutoRefFromAlloc(const wxObjcAutoRefFromAlloc& otherRef)
     :   m_ptr(otherRef.m_ptr)
-    {   ObjcRetain(m_ptr); }
+    {   wxGCSafeRetain(m_ptr); }
     ~wxObjcAutoRefFromAlloc()
-    {   ObjcRelease(m_ptr); }
+    {   wxGCSafeRelease(m_ptr); }
     wxObjcAutoRefFromAlloc& operator=(const wxObjcAutoRefFromAlloc& otherRef)
-    {   ObjcRetain(otherRef.m_ptr);
-        ObjcRelease(m_ptr);
+    {   wxGCSafeRetain(otherRef.m_ptr);
+        wxGCSafeRelease(m_ptr);
         m_ptr = otherRef.m_ptr;
         return *this;
     }
     operator T() const
-    {   return m_ptr; }
+    {   return static_cast<T>(m_ptr); }
     T operator->() const
-    {   return m_ptr; }
+    {   return static_cast<T>(m_ptr); }
 protected:
-    T m_ptr;
+    /*! @field      m_ptr       The pointer to the Objective-C object
+        @discussion
+        The pointer to the Objective-C object is typed as void* to avoid compiler-generated write
+        barriers as would be used for implicitly __strong object pointers and to avoid the similar
+        read barriers as would be used for an explicitly __weak object pointer.  The write barriers
+        are useless unless this object is located in GC-managed heap which is highly unlikely.
+
+        Since we guarantee strong reference via CFRetain/CFRelease the write-barriers are not needed
+        at all, even if this object does happen to be allocated in GC-managed heap.
+     */
+    void *m_ptr;
 };
 
-// The only thing wxObjcAutoRef has to do is retain an initial object
+/*!
+    @class      wxObjcAutoRef
+    @description
+    A pointer holder that does retain its argument.
+    NOTE: It is suggest that you instead use wxObjcAutoRefFromAlloc<T> foo([aRawPointer retain])
+ */
 template <class T>
 class wxObjcAutoRef: public wxObjcAutoRefFromAlloc<T>
 {
 public:
+    /*! @method     wxObjcAutoRef
+        @description
+        Uses the underlying wxObjcAutoRefFromAlloc and simply does a typical [p retain] such that
+        in RR-mode the object is in effectively the same retain-count state as it would have been
+        coming straight from an alloc method.
+     */
     wxObjcAutoRef(T p = 0)
     :   wxObjcAutoRefFromAlloc<T>(p)
-    {   ObjcRetain(m_ptr); }
+    {   // NOTE: ObjcRetain is correct because in GC-mode it balances ObjcRelease in our superclass constructor
+        // In RR mode it does retain and the superclass does retain/release thus resulting in an overall retain.
+        ObjcRetain(static_cast<T>(wxObjcAutoRefFromAlloc<T>::m_ptr));
+    }
     ~wxObjcAutoRef() {}
     wxObjcAutoRef(const wxObjcAutoRef& otherRef)
     :   wxObjcAutoRefFromAlloc<T>(otherRef)
@@ -74,3 +233,4 @@ public:
     {   return wxObjcAutoRefFromAlloc<T>::operator=(otherRef); }
 };
 
+#endif //ndef _WX_COCOA_OBJCREF_H__