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:
parent
64d975b280
commit
6ecc2922da
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user