1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
/** Implementation of NSProtocolChecker for GNUStep
Copyright (C) 1995 Free Software Foundation, Inc.
Original by: Mike Kienenberger
Date: Jun 1998
Written: Richard Frith-Macdonald
Date: April 2004
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
<title>NSProtocolChecker class reference</title>
$Date$ $Revision$
*/
#import "common.h"
#define EXPOSE_NSProtocolChecker_IVARS 1
#import "Foundation/NSProtocolChecker.h"
#import "Foundation/NSException.h"
#import "Foundation/NSInvocation.h"
#import "Foundation/NSMethodSignature.h"
#include <objc/Protocol.h>
/**
* The NSProtocolChecker and NSProxy classes provide message filtering and
* forwarding capabilities. If you wish to ensure at runtime that a given
* object will only be sent messages in a certain protocol, you create an
* <code>NSProtocolChecker</code> instance with the protocol and the object as
* arguments-
<example>
id versatileObject = [[ClassWithManyMethods alloc] init];
id narrowObject = [NSProtocolChecker protocolCheckerWithTarget: versatileObject
protocol: @protocol(SomeSpecificProtocol)];
return narrowObject;
</example>
* This is often used in conjunction with distributed objects to expose only a
* subset of an objects methods to remote processes
*/
@implementation NSProtocolChecker
/**
* Allocates and initializes an NSProtocolChecker instance by calling
* -initWithTarget:protocol:<br />
* Autoreleases and returns the new instance.
*/
+ (id) protocolCheckerWithTarget: (NSObject*)anObject
protocol: (Protocol*)aProtocol
{
return AUTORELEASE([[NSProtocolChecker alloc] initWithTarget: anObject
protocol: aProtocol]);
}
- (void) dealloc
{
DESTROY(_myTarget);
[super dealloc];
}
- (const char *) _protocolTypeForSelector: (SEL)aSel
{
struct objc_method_description desc;
desc = GSProtocolGetMethodDescriptionRecursive(_myProtocol, aSel, YES, YES);
if (desc.name == NULL && desc.types == NULL)
{
desc = GSProtocolGetMethodDescriptionRecursive(_myProtocol, aSel, YES, NO);
}
return desc.types;
}
/**
* Forwards any message to the delegate if the method is declared in
* the checker's protocol; otherwise raises an
* <code>NSInvalidArgumentException</code>.
*/
- (void) forwardInvocation: (NSInvocation*)anInvocation
{
const char *type;
if ([self _protocolTypeForSelector: [anInvocation selector]] == NULL)
{
if (GSObjCIsInstance(_myTarget))
{
[NSException raise: NSInvalidArgumentException
format: @"<%s -%@> not declared",
protocol_getName(_myProtocol),
NSStringFromSelector([anInvocation selector])];
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"<%s +%@> not declared",
protocol_getName(_myProtocol),
NSStringFromSelector([anInvocation selector])];
}
}
[anInvocation invokeWithTarget: _myTarget];
/*
* If the method returns 'self' (ie the target object) replace the
* returned value with the protocol checker.
*/
type = [[anInvocation methodSignature] methodReturnType];
if (GSSelectorTypesMatch(type, @encode(id)))
{
id buf;
[anInvocation getReturnValue: &buf];
if (buf == _myTarget)
{
buf = self;
[anInvocation setReturnValue: &buf];
}
}
}
- (id) init
{
self = [self initWithTarget: nil protocol: nil];
return self;
}
/**
* Initializes a newly allocated NSProtocolChecker instance that will
* forward any messages in the aProtocol protocol to anObject, its
* delegate. Thus, the checker can be vended in lieu of anObject to
* restrict the messages that can be sent to anObject. If any method
* in the protocol returns anObject, the checker will replace the returned
* value with itself rather than the target object.<br />
* Returns the new instance.
*/
- (id) initWithTarget: (NSObject*)anObject protocol: (Protocol*)aProtocol
{
_myProtocol = aProtocol;
ASSIGN(_myTarget, anObject);
return self;
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
{
if (_myProtocol != nil)
{
const char *types = [self _protocolTypeForSelector: aSelector];
if (types == NULL)
{
return nil;
}
return [NSMethodSignature signatureWithObjCTypes: types];
}
return [super methodSignatureForSelector: aSelector];
}
/**
* Returns the protocol object the checker uses to verify whether a
* given message should be forwarded to its delegate.
*/
- (Protocol*) protocol
{
return _myProtocol;
}
/**
* Returns the target of the NSProtocolChecker.
*/
- (NSObject*) target
{
return _myTarget;
}
@end
|