#ifndef _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
[NSObject -alloc]'ed and thus does not need a retain
class wxObjcAutoRefBase
{
protected:
+ /*! @function ObjcRetain
+ @abstract Simply does [p retain].
+ */
static struct objc_object* ObjcRetain(struct objc_object*);
+
+ /*! @function ObjcRelease
+ @abstract Simply does [p release].
+ */
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>
class wxObjcAutoRefFromAlloc: wxObjcAutoRefBase
{
wxObjcAutoRefFromAlloc(T p = 0)
: m_ptr(p)
// 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)
: m_ptr(otherRef.m_ptr)
- { ObjcRetain(m_ptr); }
+ { wxCFRetain(m_ptr); }
~wxObjcAutoRefFromAlloc()
- { ObjcRelease(m_ptr); }
+ { wxCFRelease(m_ptr); }
wxObjcAutoRefFromAlloc& operator=(const wxObjcAutoRefFromAlloc& otherRef)
- { ObjcRetain(otherRef.m_ptr);
- ObjcRelease(m_ptr);
+ { wxCFRetain(otherRef.m_ptr);
+ wxCFRelease(m_ptr);
m_ptr = otherRef.m_ptr;
return *this;
}
operator T() const
- { return m_ptr; }
+ { return static_cast<T>(m_ptr); }
T operator->() const
- { return m_ptr; }
+ { return static_cast<T>(m_ptr); }
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>
class wxObjcAutoRef: public wxObjcAutoRefFromAlloc<T>
{
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)
: 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(const wxObjcAutoRef& otherRef)
: wxObjcAutoRefFromAlloc<T>(otherRef)
#import <Foundation/NSNotification.h>
#import <Foundation/NSString.h>
#include "wx/cocoa/objc/NSView.h"
+#include "wx/cocoa/ObjcRef.h"
// ----------------------------------------------------------------------------
// globals
@end // implementation wxNSViewNotificationObserver
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;