7a71aa1402
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51591 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
237 lines
9.5 KiB
Objective-C
237 lines
9.5 KiB
Objective-C
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: wx/cocoa/ObjcRef.h
|
|
// Purpose: wxObjcAutoRef template class
|
|
// Author: David Elliott
|
|
// Modified by:
|
|
// Created: 2004/03/28
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) 2004 David Elliott <dfe@cox.net>
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef _WX_COCOA_OBJCREF_H__
|
|
#define _WX_COCOA_OBJCREF_H__
|
|
|
|
// Reuse wxCFRef-related code (e.g. wxCFRetain/wxCFRelease)
|
|
#include "wx/mac/corefoundation/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
|
|
[NSObject -alloc]'ed and thus does not need a retain
|
|
wxObjcAutoRef: construct a reference to an object that was
|
|
either autoreleased or is retained by something else.
|
|
*/
|
|
|
|
struct objc_object;
|
|
|
|
// We must do any calls to Objective-C from an Objective-C++ source file
|
|
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*);
|
|
};
|
|
|
|
/*! @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
|
|
{
|
|
public:
|
|
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]
|
|
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
|
|
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)
|
|
{ wxGCSafeRetain(m_ptr); }
|
|
~wxObjcAutoRefFromAlloc()
|
|
{ wxGCSafeRelease(m_ptr); }
|
|
wxObjcAutoRefFromAlloc& operator=(const wxObjcAutoRefFromAlloc& otherRef)
|
|
{ wxGCSafeRetain(otherRef.m_ptr);
|
|
wxGCSafeRelease(m_ptr);
|
|
m_ptr = otherRef.m_ptr;
|
|
return *this;
|
|
}
|
|
operator T() const
|
|
{ return static_cast<T>(m_ptr); }
|
|
T operator->() const
|
|
{ return static_cast<T>(m_ptr); }
|
|
protected:
|
|
/*! @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 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;
|
|
};
|
|
|
|
/*!
|
|
@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)
|
|
{ // 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)
|
|
{}
|
|
wxObjcAutoRef(const wxObjcAutoRefFromAlloc<T>& otherRef)
|
|
: wxObjcAutoRefFromAlloc<T>(otherRef)
|
|
{}
|
|
wxObjcAutoRef& operator=(const wxObjcAutoRef& otherRef)
|
|
{ return wxObjcAutoRefFromAlloc<T>::operator=(otherRef); }
|
|
};
|
|
|
|
#endif //ndef _WX_COCOA_OBJCREF_H__
|