]> git.saurik.com Git - wxWidgets.git/commitdiff
Fix most of the Objective-C GC problems by using the stronger CFRetain/CFRelease...
authorDavid Elliott <dfe@tgwbd.org>
Wed, 6 Feb 2008 20:10:07 +0000 (20:10 +0000)
committerDavid Elliott <dfe@tgwbd.org>
Wed, 6 Feb 2008 20:10:07 +0000 (20:10 +0000)
Actually use wxObjcAutoRef for the wxNSViewNotificationObserver singleton to keep it from being finalized.

Copyright 2008 Software 2000 Ltd.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51576 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/cocoa/NSView.h
include/wx/cocoa/ObjcRef.h
include/wx/mac/corefoundation/cfref.h
src/cocoa/NSView.mm

index 9cea1d678aa52cb7aa26e97c6865b7070dd61795..4081d71eda3b1ecd49d416e7cc214c6edfa026a7 100644 (file)
@@ -21,6 +21,8 @@ typedef struct CGRect NSRect;
 typedef struct _NSRect NSRect;
 #endif
 
+struct objc_object;
+
 class wxWindow;
 
 WX_DECLARE_OBJC_HASHMAP(NSView);
@@ -32,7 +34,7 @@ public:
     void AssociateNSView(WX_NSView cocoaNSView);
     void DisassociateNSView(WX_NSView cocoaNSView);
 protected:
-    static void *sm_cocoaObserver;
+    static struct objc_object *sm_cocoaObserver;
 public:
     virtual wxWindow* GetWxWindow() const
     {   return NULL; }
index 17493d14dab1f81d685d2036024699136cfb48fe..33086d2ab82ee15d0e50514c47de547ef7a582f9 100644 (file)
 
 #ifndef _WX_COCOA_OBJCREF_H__
 #define _WX_COCOA_OBJCREF_H__
+
+// Reuse wxCFRef-related code (e.g. wxCFRetain/wxCFRelease)
+#include "wx/mac/corefoundation/cfref.h"
+
 /*
 wxObjcAutoRefFromAlloc: construct a reference to an object that was
 [NSObject -alloc]'ed and thus does not need a retain
@@ -24,12 +28,32 @@ struct objc_object;
 class wxObjcAutoRefBase
 {
 protected:
+    /*! @function   ObjcRetain
+        @abstract   Simply does [p retain].
+     */
     static struct objc_object* ObjcRetain(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
 {
@@ -37,34 +61,69 @@ 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]
+        wxCFRetain(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); }
+    {   wxCFRetain(m_ptr); }
     ~wxObjcAutoRefFromAlloc()
-    {   ObjcRelease(m_ptr); }
+    {   wxCFRelease(m_ptr); }
     wxObjcAutoRefFromAlloc& operator=(const wxObjcAutoRefFromAlloc& otherRef)
-    {   ObjcRetain(otherRef.m_ptr);
-        ObjcRelease(m_ptr);
+    {   wxCFRetain(otherRef.m_ptr);
+        wxCFRelease(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 unsuitable because they assume the pointer (e.g. this object) is located in the heap
+        which we can't guarantee and in fact most often we are used as a global.  We therefore
+        use the CFRetain/CFRelease functions which work regardless of our memory location.
+     */
+    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(wxObjcAutoRefFromAlloc<T>::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)
index 694a19d7c909ebd91321decc7d7393d995a5776f..f5251ab1c07ef335b0b7244e6ffcc0b14a503dd6 100644 (file)
 #ifndef _WX_MAC_COREFOUNDATION_CFREF_H__
 #define _WX_MAC_COREFOUNDATION_CFREF_H__
 
+// Include unistd to ensure that NULL is defined
+#include <unistd.h>
+// Include AvailabilityMacros for DEPRECATED_ATTRIBUTE
+#include <AvailabilityMacros.h>
+
 // #include <CoreFoundation/CFBase.h>
 /* Don't include CFBase.h such that this header can be included from public
  * headers with minimal namespace pollution.
index 5c4b2a5680110e7ec258e1e644a46b9766d01367..89d4c4c0c841e42c7f0bd883a0b734ec7023b095 100644 (file)
@@ -28,6 +28,7 @@
 #import <Foundation/NSNotification.h>
 #import <Foundation/NSString.h>
 #include "wx/cocoa/objc/NSView.h"
+#include "wx/cocoa/ObjcRef.h"
 
 // ----------------------------------------------------------------------------
 // globals
@@ -215,5 +216,7 @@ WX_DECLARE_GET_OBJC_CLASS(wxNSViewNotificationObserver,NSObject)
 @end // implementation wxNSViewNotificationObserver
 WX_IMPLEMENT_GET_OBJC_CLASS(wxNSViewNotificationObserver,NSObject)
 
-void *wxCocoaNSView::sm_cocoaObserver = [[WX_GET_OBJC_CLASS(wxNSViewNotificationObserver) alloc] init];
-
+// New CF-retained observer (this should have been using wxObjcAutoRefFromAlloc to begin with)
+wxObjcAutoRefFromAlloc<wxNSViewNotificationObserver*> s_cocoaNSViewObserver([[WX_GET_OBJC_CLASS(wxNSViewNotificationObserver) alloc] init]);
+// For compatibility with old code
+id wxCocoaNSView::sm_cocoaObserver = s_cocoaNSViewObserver;