]>
Commit | Line | Data |
---|---|---|
fa8114de DE |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: wx/cocoa/ObjcRef.h | |
3 | // Purpose: wxObjcAutoRef template class | |
4 | // Author: David Elliott | |
5 | // Modified by: | |
6 | // Created: 2004/03/28 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) 2004 David Elliott <dfe@cox.net> | |
65571936 | 9 | // Licence: wxWindows licence |
fa8114de DE |
10 | ///////////////////////////////////////////////////////////////////////////// |
11 | ||
256af34f DE |
12 | #ifndef _WX_COCOA_OBJCREF_H__ |
13 | #define _WX_COCOA_OBJCREF_H__ | |
ddfdef64 DE |
14 | |
15 | // Reuse wxCFRef-related code (e.g. wxCFRetain/wxCFRelease) | |
16 | #include "wx/mac/corefoundation/cfref.h" | |
17 | ||
6ecc2922 DE |
18 | // NOTE WELL: We can only know which Objective-C runtime is being used when compiling Objective-C. |
19 | // Therefore we cannot implement these functions except when compiling Objective-C. | |
20 | #ifdef __OBJC__ | |
21 | /*! @function wxGCSafeRetain | |
22 | @templatefield Type (implicit) An Objective-C class type | |
23 | @arg r Pointer to Objective-C object. May be null. | |
24 | @abstract Retains the Objective-C object, even when using Apple's garbage collector | |
25 | @discussion | |
26 | When Apple's garbage collector is enabled, the usual [obj retain] and [obj release] messages | |
27 | are ignored. Instead the collector with help from compiler-generated write-barriers tracks | |
28 | reachable objects. The write-barriers are generated when setting i-vars of C++ classes but | |
29 | they are ignored by the garbage collector unless the C++ object is in GC-managed memory. | |
30 | ||
31 | The simple solution is to use CFRetain on the Objective-C object which has been enhanced in | |
32 | GC mode to forcibly retain the object. In Retain/Release (RR) mode the CFRetain function has | |
33 | the same effect as [obj retain]. Note that GC vs. RR is selected at runtime. | |
34 | ||
35 | Take care that wxGCSafeRetain must be balanced with wxGCSafeRelease and that conversely | |
36 | wxGCSafeRelease must only be called on objects to balance wxGCSafeRetain. In particular when | |
37 | receiving an Objective-C object from an alloc or copy method take care that you must retain | |
38 | it with wxGCSafeRetain and balance the initial alloc with a standard release. | |
39 | ||
40 | Example: | |
41 | wxGCSafeRelease(m_obj); // release current object (if any) | |
42 | NSObject *obj = [[NSObject alloc] init]; | |
43 | m_obj = wxGCSafeRetain(obj); | |
44 | [obj release]; | |
45 | ||
46 | Alternatively (same effect, perhaps less clear): | |
47 | wxGCSafeRelease(m_obj); // release current object (if any) | |
48 | m_obj = wxGCSafeRetain([[NSObject alloc] init]); | |
49 | [m_obj release]; // balance alloc | |
50 | ||
51 | Consider the effect on the retain count from each statement (alloc, CFRetain, release) | |
52 | In RR mode: retainCount = 1, +1, -1 | |
53 | In GC mode: strongRetainCount = 0, +1, -0 | |
54 | ||
55 | This is a template function to ensure it is used on raw pointers and never on pointer-holder | |
56 | objects via implicit conversion operators. | |
57 | */ | |
58 | template <class Type> | |
59 | inline Type * wxGCSafeRetain(Type *r) | |
60 | { | |
61 | #ifdef __NEXT_RUNTIME__ | |
62 | return static_cast<Type*>(wxCFRetain(r)); | |
63 | #else | |
64 | return [r retain]; | |
65 | #endif | |
66 | } | |
67 | ||
68 | /*! @function wxGCSafeRelease | |
69 | @templatefield Type (implicit) An Objective-C class type | |
70 | @arg r Pointer to Objective-C object. May be null. | |
71 | @abstract Balances wxGCSafeRetain. Particularly useful with the Apple Garbage Collector. | |
72 | @discussion | |
73 | See the wxGCSafeRetain documentation for more details. | |
74 | ||
75 | Example (from wxGCSafeRetain documentation): | |
76 | wxGCSafeRelease(m_obj); // release current object (if any) | |
77 | m_obj = wxGCSafeRetain([[NSObject alloc] init]); | |
78 | [m_obj release]; // balance alloc | |
79 | ||
80 | When viewed from the start, m_obj ought to start as nil. However, the second time through | |
81 | the wxGCSafeRelease call becomes critical as it releases the retain from the first time | |
82 | through. | |
83 | ||
84 | In the destructor for this C++ object with the m_obj i-var you ought to do the following: | |
85 | wxGCSafeRelease(m_obj); | |
86 | m_obj = nil; // Not strictly needed, but safer. | |
87 | ||
88 | Under no circumstances should you balance an alloc or copy with a wxGCSafeRelease. | |
89 | */ | |
90 | template <class Type> | |
91 | inline void wxGCSafeRelease(Type *r) | |
92 | { | |
93 | #ifdef __NEXT_RUNTIME__ | |
94 | wxCFRelease(r); | |
95 | #else | |
96 | [r release]; | |
97 | #endif | |
98 | } | |
99 | #else | |
100 | // NOTE: When not compiling Objective-C, declare these functions such that they can be | |
101 | // used by other inline-implemented methods. Since those methods in turn will not actually | |
102 | // be used from non-ObjC code there is no problem. | |
103 | ||
104 | template <class Type> | |
105 | inline Type * wxGCSafeRetain(Type *r); | |
106 | ||
107 | template <class Type> | |
108 | inline void wxGCSafeRelease(Type *r); | |
109 | ||
110 | #endif //def __OBJC__ | |
111 | ||
fa8114de DE |
112 | /* |
113 | wxObjcAutoRefFromAlloc: construct a reference to an object that was | |
114 | [NSObject -alloc]'ed and thus does not need a retain | |
115 | wxObjcAutoRef: construct a reference to an object that was | |
116 | either autoreleased or is retained by something else. | |
117 | */ | |
118 | ||
119 | struct objc_object; | |
120 | ||
121 | // We must do any calls to Objective-C from an Objective-C++ source file | |
122 | class wxObjcAutoRefBase | |
123 | { | |
124 | protected: | |
ddfdef64 DE |
125 | /*! @function ObjcRetain |
126 | @abstract Simply does [p retain]. | |
127 | */ | |
fa8114de | 128 | static struct objc_object* ObjcRetain(struct objc_object*); |
ddfdef64 DE |
129 | |
130 | /*! @function ObjcRelease | |
131 | @abstract Simply does [p release]. | |
132 | */ | |
e76d459d | 133 | static void ObjcRelease(struct objc_object*); |
fa8114de DE |
134 | }; |
135 | ||
ddfdef64 DE |
136 | /*! @class wxObjcAutoRefFromAlloc |
137 | @templatefield T The type of _pointer_ (e.g. NSString*, NSRunLoop*) | |
138 | @abstract Pointer-holder for Objective-C objects | |
139 | @discussion | |
140 | When constructing this object from a raw pointer, the pointer is assumed to have | |
141 | come from an alloc-style method. That is, once you construct this object from | |
142 | the pointer you must not balance your alloc with a call to release. | |
fa8114de | 143 | |
ddfdef64 DE |
144 | This class has been carefully designed to work with both the traditional Retain/Release |
145 | and the new Garbage Collected modes. In RR-mode it will prevent the object from being | |
146 | released by managing the reference count using the retain/release semantics. In GC-mode | |
147 | it will use a method (currently CFRetain/CFRelease) to ensure the object will never be | |
148 | finalized until this object is destroyed. | |
149 | */ | |
150 | ||
fa8114de DE |
151 | template <class T> |
152 | class wxObjcAutoRefFromAlloc: wxObjcAutoRefBase | |
153 | { | |
154 | public: | |
155 | wxObjcAutoRefFromAlloc(T p = 0) | |
156 | : m_ptr(p) | |
157 | // NOTE: this is from alloc. Do NOT retain | |
ddfdef64 DE |
158 | { |
159 | // CFRetain | |
160 | // GC: Object is strongly retained and prevented from being collected | |
161 | // non-GC: Simply realizes it's an Objective-C object and calls [p retain] | |
6ecc2922 | 162 | wxGCSafeRetain(p); |
ddfdef64 DE |
163 | // ObjcRelease (e.g. [p release]) |
164 | // GC: Objective-C retain/release mean nothing in GC mode | |
165 | // non-GC: This is a normal release call, balancing the retain | |
166 | ObjcRelease(static_cast<T>(p)); | |
167 | // The overall result: | |
168 | // GC: Object is strongly retained | |
169 | // non-GC: Retain count is the same as it was (retain then release) | |
170 | } | |
fa8114de DE |
171 | wxObjcAutoRefFromAlloc(const wxObjcAutoRefFromAlloc& otherRef) |
172 | : m_ptr(otherRef.m_ptr) | |
6ecc2922 | 173 | { wxGCSafeRetain(m_ptr); } |
fa8114de | 174 | ~wxObjcAutoRefFromAlloc() |
6ecc2922 | 175 | { wxGCSafeRelease(m_ptr); } |
fa8114de | 176 | wxObjcAutoRefFromAlloc& operator=(const wxObjcAutoRefFromAlloc& otherRef) |
6ecc2922 DE |
177 | { wxGCSafeRetain(otherRef.m_ptr); |
178 | wxGCSafeRelease(m_ptr); | |
fa8114de DE |
179 | m_ptr = otherRef.m_ptr; |
180 | return *this; | |
181 | } | |
182 | operator T() const | |
ddfdef64 | 183 | { return static_cast<T>(m_ptr); } |
fa8114de | 184 | T operator->() const |
ddfdef64 | 185 | { return static_cast<T>(m_ptr); } |
fa8114de | 186 | protected: |
ddfdef64 DE |
187 | /*! @field m_ptr The pointer to the Objective-C object |
188 | @discussion | |
189 | The pointer to the Objective-C object is typed as void* to avoid compiler-generated write | |
190 | barriers as would be used for implicitly __strong object pointers and to avoid the similar | |
191 | read barriers as would be used for an explicitly __weak object pointer. The write barriers | |
6ecc2922 DE |
192 | are useless unless this object is located in GC-managed heap which is highly unlikely. |
193 | ||
194 | Since we guarantee strong reference via CFRetain/CFRelease the write-barriers are not needed | |
195 | at all, even if this object does happen to be allocated in GC-managed heap. | |
ddfdef64 DE |
196 | */ |
197 | void *m_ptr; | |
fa8114de DE |
198 | }; |
199 | ||
ddfdef64 DE |
200 | /*! |
201 | @class wxObjcAutoRef | |
202 | @description | |
203 | A pointer holder that does retain its argument. | |
204 | NOTE: It is suggest that you instead use wxObjcAutoRefFromAlloc<T> foo([aRawPointer retain]) | |
205 | */ | |
fa8114de DE |
206 | template <class T> |
207 | class wxObjcAutoRef: public wxObjcAutoRefFromAlloc<T> | |
208 | { | |
209 | public: | |
ddfdef64 DE |
210 | /*! @method wxObjcAutoRef |
211 | @description | |
212 | Uses the underlying wxObjcAutoRefFromAlloc and simply does a typical [p retain] such that | |
213 | in RR-mode the object is in effectively the same retain-count state as it would have been | |
214 | coming straight from an alloc method. | |
215 | */ | |
fa8114de DE |
216 | wxObjcAutoRef(T p = 0) |
217 | : wxObjcAutoRefFromAlloc<T>(p) | |
ddfdef64 DE |
218 | { // NOTE: ObjcRetain is correct because in GC-mode it balances ObjcRelease in our superclass constructor |
219 | // In RR mode it does retain and the superclass does retain/release thus resulting in an overall retain. | |
220 | ObjcRetain(static_cast<T>(wxObjcAutoRefFromAlloc<T>::m_ptr)); | |
221 | } | |
fa8114de DE |
222 | ~wxObjcAutoRef() {} |
223 | wxObjcAutoRef(const wxObjcAutoRef& otherRef) | |
224 | : wxObjcAutoRefFromAlloc<T>(otherRef) | |
225 | {} | |
226 | wxObjcAutoRef(const wxObjcAutoRefFromAlloc<T>& otherRef) | |
227 | : wxObjcAutoRefFromAlloc<T>(otherRef) | |
228 | {} | |
229 | wxObjcAutoRef& operator=(const wxObjcAutoRef& otherRef) | |
230 | { return wxObjcAutoRefFromAlloc<T>::operator=(otherRef); } | |
231 | }; | |
232 | ||
256af34f | 233 | #endif //ndef _WX_COCOA_OBJCREF_H__ |