// // GTMLightweightProxy.m // // Copyright 2006-2008 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy // of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. // #import "GTMLightweightProxy.h" #import "GTMDefines.h" @implementation GTMLightweightProxy - (id)initWithRepresentedObject:(id)object { // it's weak, we don't retain representedObject_ = object; return self; } - (id)init { return [self initWithRepresentedObject:nil]; } - (void)dealloc { // it's weak, we don't release representedObject_ = nil; [super dealloc]; } - (id)representedObject { // Use a local variable to avoid a bogus compiler warning. id repObject = nil; @synchronized(self) { // Even though we don't retain this object, we hang it on the lifetime // of the calling threads pool so it's lifetime is safe for at least that // long. repObject = [representedObject_ retain]; } return [repObject autorelease]; } - (void)setRepresentedObject:(id)object { @synchronized(self) { representedObject_ = object; } } // Passes any unhandled method to the represented object if it responds to that // method. - (void)forwardInvocation:(NSInvocation*)invocation { id target = [self representedObject]; // Silently discard all messages when there's no represented object if (!target) return; SEL aSelector = [invocation selector]; if ([target respondsToSelector:aSelector]) [invocation invokeWithTarget:target]; } // Gets the represented object's method signature for |selector|; necessary for // forwardInvocation. - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector { id target = [self representedObject]; if (target) { return [target methodSignatureForSelector:selector]; } else { // Apple's underlying forwarding code crashes if we return nil here. // Since we are not going to use the invocation being constructed // if there's no representedObject, a random valid NSMethodSignature is fine. return [NSObject methodSignatureForSelector:@selector(alloc)]; } } // Prevents exceptions from unknown selectors if there is no represented // object, and makes the exception come from the right place if there is one. - (void)doesNotRecognizeSelector:(SEL)selector { id target = [self representedObject]; if (target) [target doesNotRecognizeSelector:selector]; } // Checks the represented object's selectors to allow clients of the proxy to // do respondsToSelector: tests. - (BOOL)respondsToSelector:(SEL)selector { if (selector == @selector(initWithRepresentedObject:) || selector == @selector(representedObject) || selector == @selector(setRepresentedObject:) || [super respondsToSelector:selector]) { return YES; } id target = [self representedObject]; return target && [target respondsToSelector:selector]; } @end