Reputation: 33
I'm trying to implement in Objective-C a proxy for an object in the following way:
- (NSMethodSignature*) methodSignatureForSelector:(SEL)sel
{
return [_proxifiedObject methodSignatureForSelector:sel];
}
- (void) forwardInvocation:(NSInvocation *)invocation
{
char returnType = invocation.methodSignature.methodReturnType[0];
if(returnType == '@')
{
id anotherProxy = [[[MyProxy alloc] initWithInvocation:invocation] autorelease];
[invocation setReturnValue:&anotherProxy];
} else {
invocation.target = _proxifiedObject;
[invocation invoke];
}
}
Another proxy should construct the object from this invocation. But while the object is under construction we should be able to collect and store invocations to it to have a chance to process them after the object is constructed. To achieve this I should implement 2 methods: methodSignatureForSelector: and forwardInvocation:. The second is quite easy but the first is what the question is all about.
We should know the class of the proxified object to be able to provide signature but the invocation which anotherProxy is initialized with does not provide information about the returned object's class. Is there a way to obtain the class of the object which will be returned by the method using Apple's Objective-C runtime?
UPDATE:
I understand that the actual class of the returned object may be different but there may be the only class with which the method is declared. If method is declared as
- (SomeClass*) someMethod;
in the interface I expect SomeClass to be obtained.
UPDATE:
Finally I've solved my problem. The solution is not elegant but it 'just works'. I've wrote this method:
static NSMutableDictionary* dictionarySelectorsToSignatures;
+ (NSMethodSignature*) methodSignatureForUnknownClassForSelector: (SEL) sel
{
NSMethodSignature* candidate = [dictionarySelectorsToSignatures objectForKey:[NSNumber numberWithLongLong:(long long) sel]];
if(candidate == nil)
{
int classesCount = objc_getClassList(NULL, 0);
Class* classes = malloc(sizeof(Class) * classesCount);
objc_getClassList(classes, classesCount);
for(int i = 0; i < classesCount; i++)
{
if(class_getClassMethod(classes[i], @selector(instanceMethodSignatureForSelector:)) != NULL)
{
NSMethodSignature* signature = [classes[i] instanceMethodSignatureForSelector:sel];
if(signature != nil)
{
if(candidate != nil)
{
if(![candidate isEqual:signature])
{
return nil;
}
} else {
candidate = signature;
}
}
}
}
if(candidate != nil)
{
[dictionarySelectorsToSignatures setObject:candidate
forKey:[NSNumber numberWithLongLong:(long long) sel]];
}
}
return candidate;
}
This method returns signature for selector if it is not ambiguous and nil in other case. Its main con is the fact that it does not support class/list of classes modification in runtime thus it can be used only if all classes are registered and code does not modify classes (potentially risky to use it with KVO!).
Upvotes: 3
Views: 546
Reputation: 99092
Is there a way to obtain the class of the object which will be returned by the method using Apple's Objective-C runtime?
No - if a method returns a class-type, you can't know the actual - concrete - type before it has returned. With the concrete class-type being unknown, you can't find out what return type any of it's method may have.
Upvotes: 2
Reputation: 150745
You can get the actual name of the class of the object:
e.g. for an object foo
NSLog(@"foo is an object of class %@", NSStringFromClass([foo class]));
Upvotes: 0
Reputation: 6397
Here's how to check if "instance" is an NSString
if ([instance isKindOfClass:[NSString class]]( {
//do something
}
That good?
Upvotes: 0