How to get the class that the method is defined, not that of the instance that the method is called? - objective-c

[self class] returns the Class of the instance of the method being called, but is there a way to get the Class that the method is defined? Suppose Class B extends A, and b is an instance of B, I want a method in A that returns A not B, even when called from b.
edited:
I trying to create a NSObject category that has -(void)releaseProperties method, which fetches all properties defined in that class and set nil for the non-readonly object properties.
- (void)releaseProperties {
unsigned int c = 0;
objc_property_t *properties = class_copyPropertyList([self class], &c);
for(unsigned int i = 0; i < c; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
NSString *propertyType = [NSString stringWithUTF8String:property_getAttributes(property)];
if([propertyType hasPrefix:#"T#"] // is an object
&& [propertyType rangeOfString:#",R,"].location == NSNotFound // not readonly
) {
[self setValue:nil forKey:propertyName];
NSLog(#"%#.%# = %#", NSStringFromClass(cls), propertyName, [self valueForKey:propertyName]);
}
}
free(properties);
}
I want to use this method in the dealloc method, but class_copyPropertyList([self class], &c) will not return properties defined in it's superclass, so the super-dealloc chain doesn't work well. So, instead of passing [self class], I wanted to pass the class that the specific dealloc method is being called.

I don't think there's a direct way of doing this, but you can call class_getMethodImplementation_stret with the current class to get the function pointer for the method that would be called. Then walk your superclasses, calling the same function with them until it returns something different. The previous superclass will be the one that is providing the implementation for your class.
Edit: Sorry, I may have misread the question. If you are looking for the first superclass in the hierarchy that defines a method with that signature, then you can just walk the superclasses calling respondsToSelector: until one of them doesn't. The method I describe above is to find the superclass providing the implementation that is inherited, not the definition.
For example, class A could define foo:, then class B (which is a subclass of A) could override it, then class C (which is a subclass of B) could ask where foo: comes from. If you want the class that provides the definition, you want A, and should use the second approach I describe. If you want the class that provides the implementation, you want B and should use the first approach I describe.

I have a feeling that [super class] might work for you.
And if you call "[super ..." (fill in the blank with whatever you want to call) within B, you'll be calling into a method that lives in A.

Class A can just provide a method like:
- (Class) classA
{
return [A class];
}
That's not generalizable, but your question insists on a non-generalizable answer.
It's a pretty bizarre thing to want. It suggests a problem with your design. May I ask why you want it? What problem are you trying to solve?

Related

Objective-C dynamic properties at runtime?

Is it possible to create an Objective-C class that can have an arbitrary number of dynamic properties at runtime?
I want to be able to call mySpecialClass.anyProperty and intercept this inside my class to be able to provide my own custom implementation that can then return an NSString (for instance) at runtime with raising an exception. Obviously this all has to compile.
Ideal would be if I could refer to my properties using something similar to the new literal syntax, e.g. mySpecialClass["anyProperty"].
I guess in a way I want to create something like a dynamic NSDictionary with no CFDictionary backing store, that executes 2 custom methods on property getting and setting respectively, with the property name passed in to these accessor methods so they can decide what to do.
There are at least two ways to do this.
Subscripting
Use objectForKeyedSubscript: and setObject:forKeyedSubscript:
#property (nonatomic,strong) NSMutableDictionary *properties;
- (id)objectForKeyedSubscript:(id)key {
return [[self properties] valueForKey:[NSString stringWithFormat:#"%#",key]];
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key {
[[self properties] setValue:object forKey:[NSString stringWithFormat:#"%#",key]];
}
Person *p = [Person new];
p[#"name"] = #"Jon";
NSLog(#"%#",p[#"name"]);
resolveInstanceMethod:
This is the objc_sendMsg executed by the runtime for all methods:
If you look at the bottom, you have the opportunity to resolveInstanceMethod:, which lets you redirect the method call to one of your choosing. To answer your question, you need to write a generic getter and setter that looks-up a value on a dictionary ivar:
// generic getter
static id propertyIMP(id self, SEL _cmd) {
return [[self properties] valueForKey:NSStringFromSelector(_cmd)];
}
// generic setter
static void setPropertyIMP(id self, SEL _cmd, id aValue) {
id value = [aValue copy];
NSMutableString *key = [NSStringFromSelector(_cmd) mutableCopy];
// delete "set" and ":" and lowercase first letter
[key deleteCharactersInRange:NSMakeRange(0, 3)];
[key deleteCharactersInRange:NSMakeRange([key length] - 1, 1)];
NSString *firstChar = [key substringToIndex:1];
[key replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar lowercaseString]];
[[self properties] setValue:value forKey:key];
}
And then implement resolveInstanceMethod: to add the requested method to the class.
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if ([NSStringFromSelector(aSEL) hasPrefix:#"set"]) {
class_addMethod([self class], aSEL, (IMP)setPropertyIMP, "v#:#");
} else {
class_addMethod([self class], aSEL,(IMP)propertyIMP, "##:");
}
return YES;
}
You could also do it returning a NSMethodSignature for the method, which is then wrapped in a NSInvocation and passed to forwardInvocation:, but adding the method is faster.
Here is a gist that runs in CodeRunner. It doesn't handle myClass["anyProperty"] calls.
You're asking different things. If you want to be able to use the bracket syntax mySpecialClass[#"anyProperty"] on instances of your class, it is very easy. Just implement the methods:
- (id)objectForKeyedSubscript:(id)key
{
return ###something based on the key argument###
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key
{
###set something with object based on key####
}
It will be called everytime you use the bracket syntax in your source code.
Otherwise if you want to create properties at runtime, there are different ways to proceed, take a look at NSObject's forwardInvocation: method, or look at the Objective-C Runtime Reference for functions to dynamically alter a class...
Guillaume is right. forwardInvocation: is the way to go. This answer gives some more details: method_missing-like functionality in objective-c (i.e. dynamic delegation at run time)
This has even more details: Equivalent of Ruby method_missing in Objective C / iOS
And these are some other lesser known Obj-C features that might help you: Hidden features of Objective-C
Enjoy!

What is the best way output the name of the class who's method is being called?

I am aware of NSStringFromClass.
My question relates to the situation where the same method is implemented in multiple classes in an inheritance tree, and you want to debugging information as to which class it is executing from.
Example:
Let us have three classes: A-->B-->C , inheriting as displayed by the arrows.
If each of them has a method foo(), defined:
-(void) foo
{
// Do some work particular to the class it is in.
.....
//Each method ends with the debugging statement:
NSLog("In foo of class:%$",NSClassFromString([self class]));
}
The problem occurs when foo of Class B, calls [super foo]. When [super foo] (i.e. Class A) reaches the NSLog statement, [self class] returns class B, and not A.
Likewise if C called [super foo], the log statement in super would log class C.
What I want to do, is output the class whose method implementation is being executed - so if class B calls [super foo], then the log statement in [A foo] outputs Class A.
The simple way is to replace NSClassFromString with a hardcoded string representing the class name, but I was wondering if there is a better way to do this ?
You can use __PRETTY_FUNCTION__ to include both the class and the method name:
NSLog(#"Greetings from %s", __PRETTY_FUNCTION__);
I don't believe that there is a compiler-time macro for just the class name.
There might not be a macro for class, but there is __FILE__ and __LINE__ macros in the C language. They expand to the current file and line number. You can use them in NSLog. I use __PRETTY_FUNCTION__ when I remember it, but I remember __FILE__ and __LINE__ more.
Example:
NSLog( #"%s %d", __FILE__, __LINE__ );
Remember that __FILE__ isn’t an Objective-C string.
The problem occurs when foo of Class B, calls [super foo]. When [super
foo] (i.e. Class A) reaches the NSLog statement, [self class] returns
class B, and not A.
Sure. That's because self points to an object, and that object's class doesn't change just because you call a method of the superclass.
The simple way is to replace NSClassFromString with a hardcoded string
representing the class name, but I was wondering if there is a better
way to do this?
As others have pointed out, you can use a macro like __PRETTY_FUNCTION__, but I think the simple and obvious approach is the best. You know the name of the class when you're writing the code, so you can write:
NSLog("In foo of class: %#", #"ClassA");
Each of your classes has its own implementation of your method, so each one can print its own class name in the message. Something like __PRETTY_FUNCTION__ is useful when you're writing a debug macro that you're going to use in multiple functions. That's not the case here. Using the obvious approach makes it that much easier to see what's going on, and that's important during debugging (which I assume is what you're trying to do here).
i think you would have to walk up the class hierarchy using class_getSuperclass and class_getInstanceMethod, comparing differences in the methods. do that to determine the objc class, then use class_getName or NSStringFromClass to get its name.
This would look something like:
NSString* MONClassNameWhichImplementsMethod(id Self, SEL cmd);
and
- (void)method
{
NSLog(#"%# - %#",
MONGetClassWhichImplementsMethod(self, _cmd),
NSStringFromSelector(_cmd)
);
}
and
// NOT COMPILED -- FOR ILLUSTRATION ONLY
Class MONClassWhichImplementsMethod(Class cls, SEL cmd) {
assert(cls && cmd && "srsly?");
Class super = class_getSuperclass(cls);
Method m1 = class_getInstanceMethod(cls, cmd);
assert(m1 && "srsly?");
Method m2 = class_getInstanceMethod(super, cmd);
if (0 == m2) {
return cls;
}
else if (m1 != m2) {
return cls;
}
else {
return MONClassWhichImplementsMethod(super, cmd);
}
}
NSString* MONClassNameWhichImplementsMethod(id Self, SEL cmd) {
return NSStringFromClass(MONClassNameWhichImplementsMethod(Self.class, cmd));
}
if it blows up from deep recursion, you've another problem.

Objective-C subclass and base class casting

I'm going to create a base class that implements very similar functions for all of the subclasses. This was answered in a different question. But what I need to know now is if/how I can cast various functions (in the base class) to return the subclass object. This is both for a given function but also a function call in it.
(I'm working with CoreData by the way)
As a function within the base class (this is from a class that is going to become my subclass)
+(Structure *)fetchStructureByID:(NSNumber *)structureID inContext:(NSManagedObjectContext *)managedObjectContext {...}
And as a function call within a given function:
Structure *newStructure = [Structure fetchStructureByID:[currentDictionary objectForKey:#"myId"]];
inContext:managedObjectContext];
Structure is one of my subclasses, so I need to rewrite both of these so that they are "generic" and can be applied to other subclasses (whoever is calling the function).
How do I do that?
Update: I just realized that in the second part there are actually two issues. You can't change [Structure fetch...] to [self fetch...] because it is a class method, not an instance method. How do I get around that too?
If I understand your question correctly I believe the key is the [self class] idiom.
As far as your update goes requesting a way to call a class method on the current class you can use [self class]. As in:
Structure *newStructure = [[self class] fetchStructureByID:[currentDictionary
objectForKey:#"myId"]];
inContext:managedObjectContext];
EDIT: I redid this to return id per #rpetrich's comment -- much cleaner and avoids the need for -isKindOfClass: as long as you're sure of the type of the instance you're calling -createConfiguredObject on.
As for the first part, you could just return an id (pointer to any object) and document that it will return an instance of the same class it's called upon. Then in the code you need to use [self class] anywhere you instantiate a new object in a method.
e.g. if you have a -createConfiguredObject method which returns an instance of the same class it's called on, it would be implemented as follows:
// Returns an instance of the same class as the instance it was called on.
// This is true even if the method was declared in a base class.
-(id) createConfiguredObject {
Structure *newObject = [[[self class] alloc] init];
// When this method is called on a subclass newObject is actually
// an instance of that subclass
// Configure newObject
return newObject;
}
You can then use this in code as follows:
StructureSubclass *subclass = [[[StructureSubclass alloc] init] autorelease];
subclass.name = #"subclass";
// No need to cast or use isKindOfClass: here because returned object is of type id
// and documented to return instance of the same type.
StructureSubclass *configuredSubclass = [[subclass createConfiguredObject] autorelease];
configuredSubclass.name = #"configuredSubclass";
For reference, what I was referring to with -isKindOfClass: and casting to the proper subclass is as follows:
Structure *structure;
// Do stuff
// I believe structure is now pointing to an object of type StructureSubclass
// and I want to call a method only present on StructureSubclass.
if ([structure isKindOfClass:[StrucutreSubclass class]]) {
// It is indeed of type StructureSubclass (or a subclass of same)
// so cast the pointer to StructureSubclass *
StructureSubclass *subclass = (StructureSubclass *)structure;
// the name property is only available on StructureSubclass.
subclass.name = #"myname";
} else {
NSLog(#"structure was not an instance of StructureSubclass when it was expected it would be.");
// Handle error
}

Objective C class problem

I have a problem with classes. This is my code:
self.shapeClass = [HWRectangle class];
if ([_shapeClass isKindOfClass:[HWRectangle class]]) {
NSLog(#"Class created as: %s", [_shapeClass description]);
}
I thought that the program will do the logging in this case, but it doesn't. Do you have any idea why not?
because: if ([_shapeClass isKindOfClass:[HWRectangle class]])
_shapeClass should be an instance of the class you are testing, unless you are really testing for class comparisons. So, this method is instance to class comparison, not class to class comparison.
For bonus points, your format string should be: NSLog(#"Class created as: %#", [_shapeClass description])
(unless you have overridden the NSObject method (which you should not do))
isKindOfClass checks the class of a variable. You say that shapeCalls = [HWRectangle class]. The result of [HWRectangle class] is of the class "Class". So if you compare this with the class of HWRectangle you will find that the two are not the same.

Objective C run-time parameter binding

I'd like (at runtime) to bind a parameter to a function as you can do in boost::bind - a little like the following:
-(void)myFuncWithParameter:(NSString*)param {
NSLog(param);
}
-(void)init {
UIButton *helloButton = [UIButton buttonWithType:UIButtonTypeCustom];
[helloButton addTarget:self action:#selector(myFuncWithParameter:#"hello") forControlEvents:UIControlEventTouchUpInside];
}
So... I'm dynamically binding (at runtime) the value #"hello" to a parameter.
Obviously the above isn't the correct Syntax. Does anyone know if this is possible and the correct syntax?
Cheers,
Nick.
The short answer is no, or at least not at that level.
The long answer is that it is technically possible to build something akin to using NSInvocations (and/or forwardInvocation:), doing something clever in methodForSelector: and or by dynamically registering method implementations, but it is very tricky, especially if you care at all about speed.
If I had some code where building curried methods like that was really worthwhile, what I would do is something like this (written in this comment, untested);
//FIXME: In a real implementation you would do some mangling, this code will get confused if you have _s in the curried selector, and thus could be exploitable
//This method makes a unique selector by mangling the arguments
- (SEL) selectorForSelector:(SEL)bindSel withString:(NSString *)bindString {
NSString *mangle = [NSString *stringWithFormat:#"LGBind_%#_%#"], NSStringFromSelector(bindSel), bindString];
SEL retval = NSSelectorFromString(mangle);
//Register the imp. You probably want to check if it is already reg
if (![self respondsToSelector:retval]) {
class_addMethod([self class], retval, LGBind_IMP, "v#:")l
}
}
//Generic dispatcher imp
void LGBind_IMP(id self, SEL _cmd) {
NSString *selectorName = NSStringFromSelector(_cmd);
NSArray *array [selectorName componentsSeparatedByString:#"_"];
//Skip index 0; it is #"LGBind"
NSString *originalSelectorString = [array objectAtIndex:1];
NSString *originalArgString = [array objectAtIndex:2];
//Get our the SEL and the IMP
SEL originalSEL = NSSelectorFromString(originalSelectorString);
IMP originalIMP = [self methodForSelector:originalSEL];
//call the original imp
originalIMP([self class], originalSEL, originalArgString);
}
Obviously depending on your exact needs you could do things somewhere differently, for instance you could lazily by the imps in forwardInvocation, or stash data about the managled selector in a dict in the instance instead of just managling it into the selector name.
The general answer is that the target-action mechanism only allows for a target, a sender and a message that takes the sender; therefore, if you need to access data, you must get it from the target or the sender.
One option would be to create a class that represents the binding of a parameter value, a method and an object. This class would have an action that invokes the method on the object, passing the value. Use an instance of this class as the target. Here's a simplistic example:
#interface UnaryBinder : NSObject {
id target;
SEL selector;
id parameter;
}
#property id target;
#property SEL selector;
#property (retain) id parameter;
-(id)initWithTarget:(id)anObject selector:(SEL)aSelector param:(id)aParameter;
-(void)action:(id)sender;
#end
#implementation UnaryBinder
...
-(void)action:(id)sender {
[target performSelector:selector withObject:parameter];
}
#end
If you want to support an arbitrary number of parameters, you'd need to use NSInvocation (as Louis mentions) rather than performSelector:withObject. Of course, controls don't retain their targets, so you need some way of keeping the UnaryBinder around. At that point, you might as well skip the special class and just store the data in the control, as you mention in your comment about using KVP. Alternatively, factor out the action into a controller class and use an instance of that as the target. UnaryBinder and its ilk doesn't really offer any advantages when it comes to target-action. For related topics, google "higher order messaging".