Line data Source code
1 0 : /* ReleaseLockProxy.h 2 : By Jens Ayton 3 : This code is hereby placed in the public domain. 4 : */ 5 : 6 : #import "ReleaseLockProxy.h" 7 : 8 : 9 0 : #define VERBOSE 0 10 : 11 : #if VERBOSE 12 : #define VerboseLog NSLog 13 : #else 14 0 : #define VerboseLog(...) do {} while (0) 15 : #endif 16 : 17 : 18 0 : @interface ReleaseLockProxy_SignatureTemplateClass: NSObject 19 : 20 : // These exist purely to provide NSMethodSignatures for -[ReleaseLockProxy methodSignatureForSelector:]. 21 0 : + (id)initWithObject:(id<NSObject>)object name:(NSString *)name; 22 0 : + (id)initWithRetainedObject:(id<NSObject>)object name:(NSString *)name; 23 0 : + (void)rlpAllowRelease; 24 0 : + (NSString *)rlpObjectDescription; 25 : 26 : @end 27 : 28 : 29 : @implementation ReleaseLockProxy 30 : 31 : // *** Boilerplate 32 : 33 : + (id)proxyWithObject:(id<NSObject>)object name:(NSString *)name 34 : { 35 : return [[[self alloc] initWithObject:object name:name] autorelease]; 36 : } 37 : 38 : 39 : + (id)proxyWithRetainedObject:(id<NSObject>)object name:(NSString *)name 40 : { 41 : return [[[self alloc] initWithRetainedObject:object name:name] autorelease]; 42 : } 43 : 44 : 45 : - (id)initWithObject:(id<NSObject>)object name:(NSString *)name 46 : { 47 : return [self initWithRetainedObject:[object retain] name:name]; 48 : } 49 : 50 : 51 : - (id)initWithRetainedObject:(id<NSObject>)object name:(NSString *)name 52 : { 53 : if (object == nil) 54 : { 55 : NSLog(@"** ReleaseLockProxy: passed nil object, returning nil proxy."); 56 : [self release]; 57 : return nil; 58 : } 59 : 60 : // No super init for proxies. 61 : 62 : _object = object; 63 : _name = [name copy]; 64 : _locked = YES; 65 : 66 : return self; 67 : } 68 : 69 : 70 0 : - (void)dealloc 71 : { 72 : if (_locked) 73 : { 74 : NSLog(@"** ReleaseLockProxy (%@): deallocated while locked. This shouldn't happen, unless -dealloc is being called directly.", [self rlpObjectDescription]); 75 : } 76 : else 77 : { 78 : VerboseLog(@"-- ReleaseLockProxy (%@): deallocated while not locked.", [self rlpObjectDescription]); 79 : } 80 : 81 : [_object release]; 82 : [_name release]; 83 : 84 : [super dealloc]; 85 : } 86 : 87 : 88 : - (void)rlpAllowRelease 89 : { 90 : _locked = NO; 91 : } 92 : 93 : 94 : - (NSString *)rlpObjectDescription 95 : { 96 : return _name ? _name : [_object description]; 97 : } 98 : 99 : 100 : // *** Core functionality 101 : 102 0 : - (void)release 103 : { 104 : unsigned retainCount = [self retainCount]; 105 : 106 : if (_locked && retainCount == 1) 107 : { 108 : // Breakpoint here to catch what would otherwise be the last release before crashing. 109 : NSLog(@"** ReleaseLockProxy (%@): released while locked and retain count is one - intercepting retain. Something is broken.", [self rlpObjectDescription]); 110 : return; 111 : } 112 : 113 : if (_locked) 114 : { 115 : VerboseLog(@"-- ReleaseLockProxy (%@): released while locked, but retain count > 1; retain count going from %u to %u.", [self rlpObjectDescription], retainCount, retainCount - 1); 116 : } 117 : else 118 : { 119 : VerboseLog(@"-- ReleaseLockProxy (%@): released while not locked; retain count going from %u to %u.", [self rlpObjectDescription], retainCount, retainCount - 1); 120 : } 121 : 122 : [super release]; 123 : } 124 : 125 : 126 0 : - (id)autorelease 127 : { 128 : VerboseLog(@"-- ReleaseLockProxy (%@): autoreleased while %slocked and retain count at %u.", [self rlpObjectDescription], _locked ? "" : "not ", [self retainCount]); 129 : return [super autorelease]; 130 : } 131 : 132 : 133 : // *** Proxy stuff. 134 : 135 0 : - (void)forwardInvocation:(NSInvocation *)invocation 136 : { 137 : [invocation invokeWithTarget:_object]; 138 : } 139 : 140 : 141 0 : - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector 142 : { 143 : NSMethodSignature *result = nil; 144 : 145 : if (selector == @selector(initWithObject:name:) || 146 : selector == @selector(initWithRetainedObject:name:) || 147 : selector == @selector(rlpAllowRelease) || 148 : selector == @selector(rlpObjectDescription)) 149 : { 150 : result = [ReleaseLockProxy_SignatureTemplateClass methodSignatureForSelector:selector]; 151 : } 152 : else 153 : { 154 : result = [(id)_object methodSignatureForSelector:selector]; 155 : } 156 : 157 : return result; 158 : } 159 : 160 : 161 0 : + (BOOL)instancesRespondToSelector:(SEL)selector 162 : { 163 : if (selector == @selector(initWithObject:name:) || 164 : selector == @selector(initWithRetainedObject:name:) || 165 : selector == @selector(rlpAllowRelease) || 166 : selector == @selector(rlpObjectDescription)) 167 : { 168 : return YES; 169 : } 170 : else 171 : { 172 : return NO; 173 : } 174 : } 175 : 176 : 177 0 : - (BOOL)respondsToSelector:(SEL)selector 178 : { 179 : return [ReleaseLockProxy instancesRespondToSelector:selector]; 180 : } 181 : 182 : @end 183 : 184 : 185 : @implementation ReleaseLockProxy_SignatureTemplateClass 186 : 187 : + (id)initWithObject:(id<NSObject>)object name:(NSString *)name { return nil; } 188 : + (id)initWithRetainedObject:(id<NSObject>)object name:(NSString *)name { return nil; } 189 : + (void)rlpAllowRelease { } 190 : + (NSString *)rlpObjectDescription { return nil; } 191 : 192 : @end