Line data Source code
1 0 : /* 2 : 3 : OOWeakReference.m 4 : 5 : Written by Jens Ayton in 2007-2013 for Oolite. 6 : This code is hereby placed in the public domain. 7 : 8 : */ 9 : 10 : #import "OOWeakReference.h" 11 : 12 : 13 0 : @interface OOWeakReferenceTemplates: NSObject 14 : 15 0 : + (void)weakRefDrop; 16 0 : + (id)weakRefUnderlyingObject; 17 0 : + (id)nilMethod; 18 : 19 : @end 20 : 21 : 22 : @implementation OOWeakReference 23 : 24 : // *** Core functionality. 25 : 26 : + (id)weakRefWithObject:(id<OOWeakReferenceSupport>)object 27 : { 28 : if (object == nil) return nil; 29 : 30 : OOWeakReference *result = [OOWeakReference alloc]; 31 : // No init for proxies. 32 : result->_object = object; 33 : return [result autorelease]; 34 : } 35 : 36 : 37 0 : - (void)dealloc 38 : { 39 : [_object weakRefDied:self]; 40 : 41 : [super dealloc]; 42 : } 43 : 44 : 45 0 : - (NSString *)description 46 : { 47 : if (_object != nil) return [_object description]; 48 : else return [NSString stringWithFormat:@"<Dead %@ %p>", [self class], self]; 49 : } 50 : 51 : 52 : - (id)weakRefUnderlyingObject 53 : { 54 : return _object; 55 : } 56 : 57 : 58 0 : - (id)weakRetain 59 : { 60 : return [self retain]; 61 : } 62 : 63 : 64 : - (void)weakRefDrop 65 : { 66 : _object = nil; 67 : } 68 : 69 : 70 : // *** Proxy evilness beyond this point. 71 : 72 0 : - (Class) class 73 : { 74 : return [_object class]; 75 : } 76 : 77 : 78 0 : - (BOOL) isProxy 79 : { 80 : return YES; 81 : } 82 : 83 : 84 0 : - (void)forwardInvocation:(NSInvocation *)invocation 85 : { 86 : // Does the right thing even with nil _object. 87 : [invocation invokeWithTarget:_object]; 88 : } 89 : 90 : 91 0 : - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector 92 : { 93 : NSMethodSignature *result = nil; 94 : 95 : if (__builtin_expect( 96 : selector != @selector(weakRefDrop) && 97 : selector != @selector(weakRefUnderlyingObject), 1)) 98 : { 99 : // Not a proxy method; get signature from _object if it exists, otherwise generic signature for nil calls. 100 : if (__builtin_expect(_object != nil, 1)) result = [(id)_object methodSignatureForSelector:selector]; 101 : else result = [OOWeakReferenceTemplates methodSignatureForSelector:@selector(nilMethod)]; 102 : } 103 : else 104 : { 105 : // One of OOWeakReference's own methods. 106 : result = [OOWeakReferenceTemplates methodSignatureForSelector:selector]; 107 : } 108 : 109 : return result; 110 : } 111 : 112 : 113 0 : - (BOOL)respondsToSelector:(SEL)selector 114 : { 115 : if (__builtin_expect(_object != nil && 116 : selector != @selector(weakRefDrop) && 117 : selector != @selector(weakRefUnderlyingObject), 1)) 118 : { 119 : // _object exists and it's not one of our methods, ask _object. 120 : return [_object respondsToSelector:selector]; 121 : } 122 : else 123 : { 124 : // Selector we responds to, or _object is nil and therefore responds to everything. 125 : return YES; 126 : } 127 : } 128 : 129 : 130 : // New fast forwarding mechanism introduced in Mac OS X 10.5. 131 : // Note that -forwardInvocation: is still called if _object is nil. 132 0 : - (id)forwardingTargetForSelector:(SEL)sel 133 : { 134 : return _object; 135 : } 136 : 137 : @end 138 : 139 : 140 : @implementation NSObject (OOWeakReference) 141 : 142 : - (id)weakRefUnderlyingObject 143 : { 144 : return self; 145 : } 146 : 147 : @end 148 : 149 : 150 : @implementation OOWeakRefObject 151 : 152 0 : - (id)weakRetain 153 : { 154 : if (weakSelf == nil) weakSelf = [OOWeakReference weakRefWithObject:self]; 155 : return [weakSelf retain]; // Each caller releases this, as -weakRetain must be balanced with -release. 156 : } 157 : 158 : 159 0 : - (void)weakRefDied:(OOWeakReference *)weakRef 160 : { 161 : if (weakRef == weakSelf) weakSelf = nil; 162 : } 163 : 164 : 165 0 : - (void)dealloc 166 : { 167 : [weakSelf weakRefDrop]; // Very important! 168 : [super dealloc]; 169 : } 170 : 171 : 172 : - (id)weakSelf 173 : { 174 : return [[self weakRetain] autorelease]; 175 : } 176 : 177 : @end 178 : 179 : 180 : @implementation OOWeakReferenceTemplates 181 : 182 : // These are never called, but an implementation must exist so that -methodSignatureForSelector: works. 183 : + (void)weakRefDrop {} 184 : + (id)weakRefUnderlyingObject { return nil; } 185 : + (id)nilMethod { return nil; } 186 : 187 : @end