// Name: wx/cocoa/ObjcRef.h
// Purpose: wxObjcAutoRef template class
// Author: David Elliott
-// Modified by:
+// Modified by:
// Created: 2004/03/28
// RCS-ID: $Id$
// Copyright: (c) 2004 David Elliott <dfe@cox.net>
#define _WX_COCOA_OBJCREF_H__
// Reuse wxCFRef-related code (e.g. wxCFRetain/wxCFRelease)
-#include "wx/mac/corefoundation/cfref.h"
+#include "wx/osx/core/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
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
{
// 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
}
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;
}
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;
};