Fix most of the Objective-C GC problems by using the stronger CFRetain/CFRelease in wxObjcAutoRef.
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
This commit is contained in:
@@ -21,6 +21,8 @@ typedef struct CGRect NSRect;
|
|||||||
typedef struct _NSRect NSRect;
|
typedef struct _NSRect NSRect;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct objc_object;
|
||||||
|
|
||||||
class wxWindow;
|
class wxWindow;
|
||||||
|
|
||||||
WX_DECLARE_OBJC_HASHMAP(NSView);
|
WX_DECLARE_OBJC_HASHMAP(NSView);
|
||||||
@@ -32,7 +34,7 @@ public:
|
|||||||
void AssociateNSView(WX_NSView cocoaNSView);
|
void AssociateNSView(WX_NSView cocoaNSView);
|
||||||
void DisassociateNSView(WX_NSView cocoaNSView);
|
void DisassociateNSView(WX_NSView cocoaNSView);
|
||||||
protected:
|
protected:
|
||||||
static void *sm_cocoaObserver;
|
static struct objc_object *sm_cocoaObserver;
|
||||||
public:
|
public:
|
||||||
virtual wxWindow* GetWxWindow() const
|
virtual wxWindow* GetWxWindow() const
|
||||||
{ return NULL; }
|
{ return NULL; }
|
||||||
|
@@ -11,6 +11,10 @@
|
|||||||
|
|
||||||
#ifndef _WX_COCOA_OBJCREF_H__
|
#ifndef _WX_COCOA_OBJCREF_H__
|
||||||
#define _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
|
wxObjcAutoRefFromAlloc: construct a reference to an object that was
|
||||||
[NSObject -alloc]'ed and thus does not need a retain
|
[NSObject -alloc]'ed and thus does not need a retain
|
||||||
@@ -24,11 +28,31 @@ struct objc_object;
|
|||||||
class wxObjcAutoRefBase
|
class wxObjcAutoRefBase
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
/*! @function ObjcRetain
|
||||||
|
@abstract Simply does [p retain].
|
||||||
|
*/
|
||||||
static struct objc_object* ObjcRetain(struct objc_object*);
|
static struct objc_object* ObjcRetain(struct objc_object*);
|
||||||
|
|
||||||
|
/*! @function ObjcRelease
|
||||||
|
@abstract Simply does [p release].
|
||||||
|
*/
|
||||||
static void ObjcRelease(struct objc_object*);
|
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>
|
template <class T>
|
||||||
class wxObjcAutoRefFromAlloc: wxObjcAutoRefBase
|
class wxObjcAutoRefFromAlloc: wxObjcAutoRefBase
|
||||||
@@ -37,34 +61,69 @@ public:
|
|||||||
wxObjcAutoRefFromAlloc(T p = 0)
|
wxObjcAutoRefFromAlloc(T p = 0)
|
||||||
: m_ptr(p)
|
: m_ptr(p)
|
||||||
// NOTE: this is from alloc. Do NOT retain
|
// 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)
|
wxObjcAutoRefFromAlloc(const wxObjcAutoRefFromAlloc& otherRef)
|
||||||
: m_ptr(otherRef.m_ptr)
|
: m_ptr(otherRef.m_ptr)
|
||||||
{ ObjcRetain(m_ptr); }
|
{ wxCFRetain(m_ptr); }
|
||||||
~wxObjcAutoRefFromAlloc()
|
~wxObjcAutoRefFromAlloc()
|
||||||
{ ObjcRelease(m_ptr); }
|
{ wxCFRelease(m_ptr); }
|
||||||
wxObjcAutoRefFromAlloc& operator=(const wxObjcAutoRefFromAlloc& otherRef)
|
wxObjcAutoRefFromAlloc& operator=(const wxObjcAutoRefFromAlloc& otherRef)
|
||||||
{ ObjcRetain(otherRef.m_ptr);
|
{ wxCFRetain(otherRef.m_ptr);
|
||||||
ObjcRelease(m_ptr);
|
wxCFRelease(m_ptr);
|
||||||
m_ptr = otherRef.m_ptr;
|
m_ptr = otherRef.m_ptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
operator T() const
|
operator T() const
|
||||||
{ return m_ptr; }
|
{ return static_cast<T>(m_ptr); }
|
||||||
T operator->() const
|
T operator->() const
|
||||||
{ return m_ptr; }
|
{ return static_cast<T>(m_ptr); }
|
||||||
protected:
|
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>
|
template <class T>
|
||||||
class wxObjcAutoRef: public wxObjcAutoRefFromAlloc<T>
|
class wxObjcAutoRef: public wxObjcAutoRefFromAlloc<T>
|
||||||
{
|
{
|
||||||
public:
|
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)
|
wxObjcAutoRef(T p = 0)
|
||||||
: wxObjcAutoRefFromAlloc<T>(p)
|
: 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() {}
|
||||||
wxObjcAutoRef(const wxObjcAutoRef& otherRef)
|
wxObjcAutoRef(const wxObjcAutoRef& otherRef)
|
||||||
: wxObjcAutoRefFromAlloc<T>(otherRef)
|
: wxObjcAutoRefFromAlloc<T>(otherRef)
|
||||||
|
@@ -17,6 +17,11 @@
|
|||||||
#ifndef _WX_MAC_COREFOUNDATION_CFREF_H__
|
#ifndef _WX_MAC_COREFOUNDATION_CFREF_H__
|
||||||
#define _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>
|
// #include <CoreFoundation/CFBase.h>
|
||||||
/* Don't include CFBase.h such that this header can be included from public
|
/* Don't include CFBase.h such that this header can be included from public
|
||||||
* headers with minimal namespace pollution.
|
* headers with minimal namespace pollution.
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#import <Foundation/NSNotification.h>
|
#import <Foundation/NSNotification.h>
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
#include "wx/cocoa/objc/NSView.h"
|
#include "wx/cocoa/objc/NSView.h"
|
||||||
|
#include "wx/cocoa/ObjcRef.h"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// globals
|
// globals
|
||||||
@@ -215,5 +216,7 @@ WX_DECLARE_GET_OBJC_CLASS(wxNSViewNotificationObserver,NSObject)
|
|||||||
@end // implementation wxNSViewNotificationObserver
|
@end // implementation wxNSViewNotificationObserver
|
||||||
WX_IMPLEMENT_GET_OBJC_CLASS(wxNSViewNotificationObserver,NSObject)
|
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;
|
||||||
|
Reference in New Issue
Block a user