Instead of using wxCFRetain/wxCFRelease directly for Objective-C objects add

new wxGCSafeRetain/wxGCSafeRelease functions which are specific to Objective-C
objects and can be compile-time switched to standard retain/release without
breaking wxCFRetain/wxCFRelease for CF objects.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51584 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
David Elliott 2008-02-07 23:37:30 +00:00
parent 64d975b280
commit 6ecc2922da

View File

@ -15,6 +15,100 @@
// Reuse wxCFRef-related code (e.g. wxCFRetain/wxCFRelease)
#include "wx/mac/corefoundation/cfref.h"
// NOTE WELL: We can only know which Objective-C runtime is being 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 __NEXT_RUNTIME__
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 __NEXT_RUNTIME__
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 there is no problem.
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
@ -65,7 +159,7 @@ public:
// 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);
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
@ -76,12 +170,12 @@ public:
}
wxObjcAutoRefFromAlloc(const wxObjcAutoRefFromAlloc& otherRef)
: m_ptr(otherRef.m_ptr)
{ wxCFRetain(m_ptr); }
{ wxGCSafeRetain(m_ptr); }
~wxObjcAutoRefFromAlloc()
{ wxCFRelease(m_ptr); }
{ wxGCSafeRelease(m_ptr); }
wxObjcAutoRefFromAlloc& operator=(const wxObjcAutoRefFromAlloc& otherRef)
{ wxCFRetain(otherRef.m_ptr);
wxCFRelease(m_ptr);
{ wxGCSafeRetain(otherRef.m_ptr);
wxGCSafeRelease(m_ptr);
m_ptr = otherRef.m_ptr;
return *this;
}
@ -95,9 +189,10 @@ protected:
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.
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;
};