X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ddfdef64fadb32a8c122977ff70669a9d8d5a37d..a01ada0599acdc11497850c4c8e846d3f237bf91:/include/wx/cocoa/ObjcRef.h diff --git a/include/wx/cocoa/ObjcRef.h b/include/wx/cocoa/ObjcRef.h index 33086d2ab8..f08c6435dd 100644 --- a/include/wx/cocoa/ObjcRef.h +++ b/include/wx/cocoa/ObjcRef.h @@ -13,7 +13,104 @@ #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 +inline Type * wxGCSafeRetain(Type *r) +{ +#ifdef __OBJC_GC__ + return static_cast(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 +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 +inline Type * wxGCSafeRetain(Type *r); + +template +inline void wxGCSafeRelease(Type *r); + +#endif //def __OBJC__ /* wxObjcAutoRefFromAlloc: construct a reference to an object that was @@ -65,7 +162,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 +173,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 +192,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; };