]>
Commit | Line | Data |
---|---|---|
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> | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | #ifndef _WX_COCOA_OBJCREF_H__ | |
13 | #define _WX_COCOA_OBJCREF_H__ | |
14 | ||
15 | // Reuse wxCFRef-related code (e.g. wxCFRetain/wxCFRelease) | |
16 | #include "wx/mac/corefoundation/cfref.h" | |
17 | ||
18 | // NOTE WELL: We can only know whether or not GC can be 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 __OBJC_GC__ | |
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 __OBJC_GC__ | |
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 the compiler ought not emit them. If it emits an out of | |
103 | // line copy of those methods then presumably it will have also emitted at least one | |
104 | // out of line copy of these functions from at least one Objective-C++ translation unit. | |
105 | // That means the out of line implementation will be available at link time. | |
106 | ||
107 | template <class Type> | |
108 | inline Type * wxGCSafeRetain(Type *r); | |
109 | ||
110 | template <class Type> | |
111 | inline void wxGCSafeRelease(Type *r); | |
112 | ||
113 | #endif //def __OBJC__ | |
114 | ||
115 | /* | |
116 | wxObjcAutoRefFromAlloc: construct a reference to an object that was | |
117 | [NSObject -alloc]'ed and thus does not need a retain | |
118 | wxObjcAutoRef: construct a reference to an object that was | |
119 | either autoreleased or is retained by something else. | |
120 | */ | |
121 | ||
122 | struct objc_object; | |
123 | ||
124 | // We must do any calls to Objective-C from an Objective-C++ source file | |
125 | class wxObjcAutoRefBase | |
126 | { | |
127 | protected: | |
128 | /*! @function ObjcRetain | |
129 | @abstract Simply does [p retain]. | |
130 | */ | |
131 | static struct objc_object* ObjcRetain(struct objc_object*); | |
132 | ||
133 | /*! @function ObjcRelease | |
134 | @abstract Simply does [p release]. | |
135 | */ | |
136 | static void ObjcRelease(struct objc_object*); | |
137 | }; | |
138 | ||
139 | /*! @class wxObjcAutoRefFromAlloc | |
140 | @templatefield T The type of _pointer_ (e.g. NSString*, NSRunLoop*) | |
141 | @abstract Pointer-holder for Objective-C objects | |
142 | @discussion | |
143 | When constructing this object from a raw pointer, the pointer is assumed to have | |
144 | come from an alloc-style method. That is, once you construct this object from | |
145 | the pointer you must not balance your alloc with a call to release. | |
146 | ||
147 | This class has been carefully designed to work with both the traditional Retain/Release | |
148 | and the new Garbage Collected modes. In RR-mode it will prevent the object from being | |
149 | released by managing the reference count using the retain/release semantics. In GC-mode | |
150 | it will use a method (currently CFRetain/CFRelease) to ensure the object will never be | |
151 | finalized until this object is destroyed. | |
152 | */ | |
153 | ||
154 | template <class T> | |
155 | class wxObjcAutoRefFromAlloc: wxObjcAutoRefBase | |
156 | { | |
157 | public: | |
158 | wxObjcAutoRefFromAlloc(T p = 0) | |
159 | : m_ptr(p) | |
160 | // NOTE: this is from alloc. Do NOT retain | |
161 | { | |
162 | // CFRetain | |
163 | // GC: Object is strongly retained and prevented from being collected | |
164 | // non-GC: Simply realizes it's an Objective-C object and calls [p retain] | |
165 | wxGCSafeRetain(p); | |
166 | // ObjcRelease (e.g. [p release]) | |
167 | // GC: Objective-C retain/release mean nothing in GC mode | |
168 | // non-GC: This is a normal release call, balancing the retain | |
169 | ObjcRelease(static_cast<T>(p)); | |
170 | // The overall result: | |
171 | // GC: Object is strongly retained | |
172 | // non-GC: Retain count is the same as it was (retain then release) | |
173 | } | |
174 | wxObjcAutoRefFromAlloc(const wxObjcAutoRefFromAlloc& otherRef) | |
175 | : m_ptr(otherRef.m_ptr) | |
176 | { wxGCSafeRetain(m_ptr); } | |
177 | ~wxObjcAutoRefFromAlloc() | |
178 | { wxGCSafeRelease(m_ptr); } | |
179 | wxObjcAutoRefFromAlloc& operator=(const wxObjcAutoRefFromAlloc& otherRef) | |
180 | { wxGCSafeRetain(otherRef.m_ptr); | |
181 | wxGCSafeRelease(m_ptr); | |
182 | m_ptr = otherRef.m_ptr; | |
183 | return *this; | |
184 | } | |
185 | operator T() const | |
186 | { return static_cast<T>(m_ptr); } | |
187 | T operator->() const | |
188 | { return static_cast<T>(m_ptr); } | |
189 | protected: | |
190 | /*! @field m_ptr The pointer to the Objective-C object | |
191 | @discussion | |
192 | The pointer to the Objective-C object is typed as void* to avoid compiler-generated write | |
193 | barriers as would be used for implicitly __strong object pointers and to avoid the similar | |
194 | read barriers as would be used for an explicitly __weak object pointer. The write barriers | |
195 | are useless unless this object is located in GC-managed heap which is highly unlikely. | |
196 | ||
197 | Since we guarantee strong reference via CFRetain/CFRelease the write-barriers are not needed | |
198 | at all, even if this object does happen to be allocated in GC-managed heap. | |
199 | */ | |
200 | void *m_ptr; | |
201 | }; | |
202 | ||
203 | /*! | |
204 | @class wxObjcAutoRef | |
205 | @description | |
206 | A pointer holder that does retain its argument. | |
207 | NOTE: It is suggest that you instead use wxObjcAutoRefFromAlloc<T> foo([aRawPointer retain]) | |
208 | */ | |
209 | template <class T> | |
210 | class wxObjcAutoRef: public wxObjcAutoRefFromAlloc<T> | |
211 | { | |
212 | public: | |
213 | /*! @method wxObjcAutoRef | |
214 | @description | |
215 | Uses the underlying wxObjcAutoRefFromAlloc and simply does a typical [p retain] such that | |
216 | in RR-mode the object is in effectively the same retain-count state as it would have been | |
217 | coming straight from an alloc method. | |
218 | */ | |
219 | wxObjcAutoRef(T p = 0) | |
220 | : wxObjcAutoRefFromAlloc<T>(p) | |
221 | { // NOTE: ObjcRetain is correct because in GC-mode it balances ObjcRelease in our superclass constructor | |
222 | // In RR mode it does retain and the superclass does retain/release thus resulting in an overall retain. | |
223 | ObjcRetain(static_cast<T>(wxObjcAutoRefFromAlloc<T>::m_ptr)); | |
224 | } | |
225 | ~wxObjcAutoRef() {} | |
226 | wxObjcAutoRef(const wxObjcAutoRef& otherRef) | |
227 | : wxObjcAutoRefFromAlloc<T>(otherRef) | |
228 | {} | |
229 | wxObjcAutoRef(const wxObjcAutoRefFromAlloc<T>& otherRef) | |
230 | : wxObjcAutoRefFromAlloc<T>(otherRef) | |
231 | {} | |
232 | wxObjcAutoRef& operator=(const wxObjcAutoRef& otherRef) | |
233 | { return wxObjcAutoRefFromAlloc<T>::operator=(otherRef); } | |
234 | }; | |
235 | ||
236 | #endif //ndef _WX_COCOA_OBJCREF_H__ |