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