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

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.

Related

Class issues: should I use everywhere self as class in objective c?

Wow, great issue I have found for myself.
What is it? The candy or the garlic?
something about Objective-C:
Are there any issues not to use 'self' in (+) - class methods as class?
in the deep of a class...
+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval {
return [self dateWithTimeIntervalSince1970:interval];
}
Ruby here:
For example, in Ruby everything is object and class is object of class Class and there is a good practice to rely on self:
class DateClass
# self is DateClass here, inside of class definition, uh
self.dateWithTimeInterval(interval)
self.dateWithTimeIntervalSince1970(interval)
end
end
Perl here:
Another example was found in perl oop deep: (thanks for this thread)
sub new {
my $proto = shift || die "Must pass a class or object into new()";
my $class = ref($proto) || $proto;
bless {}, $class;
}
So, in Perl and in Ruby guys always rely on $class refs
Maybe example with Perl code not obvious, but it happens all time. Programmers rely on $class reference and take class name with it. also, they can invoke some methods with it:
my $class = 'Class';
$class->new();
or
Class::->new()
After all...
Which pitfalls or caveats could you provide against usage self as class in objective-c?
Usually you use self whenever you can but of course, there are situations when referencing the class by [MyClass class] is desired. Almost all of the scenarios are related to inheritance.
For example, a creator method for a class A.
#implementation A
+ (id)createInstanceWithParam:(NSInteger)param {
return [[self alloc] initWithParam:param];
}
#end
Will work correctly even if we create a subclass B. However, if we decide to implement a class cluster, then we have to reference classes by names:
#implementation SomeDataStructure
+ (id)createInstanceWithType:(NSInteger)type {
if (type == 0) {
return [[DataStructureImpl1 alloc] init];
}
else if (type == 1) {
return [[DataStructureImpl2 alloc] init];
}
}
#end
Another example is the common example of +initialize
+ (void)initialize {
if (self == [MyClass class]) {
...perform initialization...
}
}
And of course, if you are overriding a method, then using self or using [MySelf class] can be a distinction between your overriden implementation and the original implementation. Although super could be used there, too.
TLDR:
self is preferred but be careful with subclasses/superclasses.
For understanding pros and cons of using self vs. class name let's consider one situation:
Class A is subclass of NSDate and implements method +(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval.
Class B is subclass of A and overrides implementation of +dateWithTimeIntervalSince1970:(NSTimeInterval)interval method that declared in NSDate.
Now let's consider two possible implementations of +(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval method in A:
1. Using self
+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval {
return [self dateWithTimeIntervalSince1970:interval];
}
if run [B dateWithTimeInterval:interval]; then self in above code is kind of B class and as expected custom implementation (in class B) for +(NSDate*)dateWithTimeIntervalSince1970:(NSTimeInterval)interval method would be called.
2. Using directly NSDate
+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval {
return [NSDate dateWithTimeIntervalSince1970:interval];
}
if run [B dateWithTimeInterval:interval]; then overridden implementation (in class B) would be ignored and instead of it: original implementation (in class NSDate) for +(NSDate*)dateWithTimeIntervalSince1970:(NSTimeInterval)interval method would be called. It's so because we directly send message to NSDate: [NSDate dateWithTimeIntervalSince1970:interval];.
This behavior is unexpected for developer.
For the same reason declare methods in such way:
+(instancetype)dateWithTimeInterval:(NSTimeInterval)interval {
return [self dateWithTimeIntervalSince1970:interval];
}
By using instancetype compiler will know what kind of object is returned by method-initializer. When you call [B dateWithTimeInterval:interval] it returns object of kind B but not NSDate.

How to treat NSArray of mixed content as of unified content?

Class B is derived from Class A.
Class B overrides '- (NSString *) description', overridden in Class A too.
I made a new 'NSArray' of pointers to instances, both Class A and Class B.
Is it possible to treat all of them in a cycle as Class A instances, more precisely - is it possible to use Class A '- (NSString *) description' for all of them?
Currently, I use a check if it's a Class B instance, and call initializer that makes Class A instance in that case. But it seems unnecessary, I don't like this solution.
Yes you can do it.
for (ClassA item in myMixedArray)
NSLog("#%", item.description);
This is valid if myMixedArray has elements of ClassA, ClassB. In fact (although not correct and very confusing) it works for any class or object pointer, even if they are unrelated to Class A or B. The only issue is making sure that item implements description, otherwise it will fail.
In your specific case it is very safe, because any element would somehow be a ClassA object (either directly or inherited).
If some day you need to have totally unrelated objects you can use id as the iterator type.
for (id item in myMixedArray)
[id someMethodThatAllObjectsImplement];
EDIT (to clarify misunderstood question):
In Objective-C there's no easy way to force a call on the base class implementation, unlike C++, even type casting the pointer will prove useless. There's a tricky way to force calling the base class implementation explained on this question.
The following example may be a little easier on the eyes than the solution in the other thread mentioned in Merlevede's answer.
for ( id item in array )
{
if ( [item isMemberOfClass:[ClassA class]] )
{
NSLog( #"%#", item );
}
else
{
struct objc_super parent = { item, [item superclass] };
NSLog( #"%#", objc_msgSendSuper( &parent, #selector(description) ) );
}
}
The objc_msgSendSuper function can be used to call any method that returns an id
Edit - forgot to mention that you need to
#import <objc/message.h>
Edit 2 - based on feedback from OP in the comments, here is the ultimate solution
for ( id item in array )
{
struct objc_super baseClass = { item, [ClassA class] };
NSLog( #"%#", objc_msgSendSuper( &baseClass, #selector(description) ) );
}

Using objc_msgSendSuper to invoke a class method

I was going through and replacing #synthesized(self) locks w/ this method
void _ThreadsafeInit(Class theClassToInit, void *volatile *theVariableItLivesIn, void(^InitBlock)(void))
{
//this is what super does :X
struct objc_super mySuper = {
.receiver = (id)theClassToInit,
.super_class = class_getSuperclass(theClassToInit)
};
id (*objc_superAllocTyped)(struct objc_super *, SEL, NSZone *) = (void *)&objc_msgSendSuper;
// id (*objc_superAllocTyped)(id objc_super, SEL, NSZone *) = (void *)&objc_msgSend;
do {
id temp = [(*objc_superAllocTyped)(&mySuper /*theClassToInit*/, #selector(allocWithZone:), NULL) init];//get superclass in case alloc is blocked in this class;
if(OSAtomicCompareAndSwapPtrBarrier(0x0, temp, theVariableItLivesIn)) { //atomic operation forces synchronization
if( InitBlock != NULL ) {
InitBlock(); //only the thread that succesfully set sharedInstance pointer gets here
}
break;
}
else
{
[temp release]; //any thread that fails to set sharedInstance needs to clean up after itself
}
} while (*theVariableItLivesIn == NULL);
}
which while a bit more verbose exhibits significantly better performance in non-contested cases
along with this little macro (excuse poor formatting, it's very simple). To allow the block to be declared after the initial nil check, looks to help LLVM keep the "already initialized" path extremely fast. That's the only one I care about.
#define ThreadsafeFastInit(theClassToInit, theVariableToStoreItIn, aVoidBlockToRunAfterInit) if( theVariableToStoreItIn == nil) { _ThreadsafeInitWithBlock(theClassToInit, (void *)&theVariableToStoreItIn, aVoidBlockToRunAfterInit); }
So initially implemented it using the commented out sections for objc_superAllocTyped (actually first using [theClassToInit allocWithZone:NULL], which was definitely the best approach :) ), which worked great until I realized that most of the singletons in the project had overridden allocWithZone to return the singleton method... infinite loop. So I figured using objc_msgSendSuper should sort it out quickly, but I get this error.
[51431:17c03] +[DataUtils allocWithZone:]: unrecognized selector sent to class 0x4f9584
The error doesn't seem to be related to the actual problem, as...
(lldb) po 0x4f9584
$1 = 5215620 DataUtils
(lldb) print (BOOL)[$1 respondsToSelector:#selector(allocWithZone:)]
(BOOL) $2 = YES
So I'm definitely missing something... I compared to assembly generated by a [super allocWithZone:NULL] method in an empty class... almost identical except for the functions called have different names (maybe just using different symbols, no idea, can't read it that well).
Any ideas? I can use class_getClassMethod on the superclass and call the IMP directly, but I'm trying to be reasonable in my abuse of the runtime :)
Alright, this wasn't actually that tricky once I recalled that the meta class contains all of the method information for a Class instance obtained via -[self class] or +[self] -> thanks http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html
This error occurred because I was asking the runtime to look up the method in NSObject's set of instance methods, which obviously doesn't contain allocWithZone: . The mistake in the error log presumably originated because the receiver was a metaclass instance, and Apple has their interns implement error logs.
so while with a normal instance method call via objc_msgSendSuper, you would pass a metaclass instance as objc_super.super_class, to invoke a class method, the metaclass itself is needed (everything is one level up).
Example, and a diagram that helped me understand this - (http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html)
struct objc_super mySuper;
mySuper.receiver = theClassToInit; //this is our receiver, no doubt about it
//either grab the super class and get its metaclass
mySuper.super_class = object_getClass( class_getSuperclass( theClassToInit ) );
//or grab the metaclass, and get its super class, this is the exact same object
mySuper.super_class = class_getSuperclass( object_getClass( theClassToInit ) );
Then the message can be resolved correctly. Makes perfect sense now that I started paying attention :P
Anyways, now that I found my mistake I feel like I've leveled up my Objc runtime understanding. I was also able to fix an architectural mistake made two years ago by someone I never met without having to modifying and re-test dozens of classes across 3 projects and 2 static libraries (God I love Objective-C). Replacing the #synchronized construct with a simple function call also halved the compiled code size of those methods. As a bonus, all our singleton accessors are now (more) threadsafe, because the performance cost for doing so is now negligible. Methods which naively re-fetched the singleton object multiple times (or in loops) have seen a huge speedup now that they don't have to acquire and release a mutex multiple times per invocation. All in all I'm very happy it all worked as I'd hoped.
I made a "normal" Objective-C method for this on a category of NSObject, which will work for both instance and Class objects to allow you to invoke a superclass's implementation of a message externally. Warning: This is only for fun, or unit tests, or swizzled methods, or maybe a really cool game.
#implementation NSObject (Convenience)
-(id)performSelector:(SEL)selector asClass:(Class)class
{
struct objc_super mySuper = {
.receiver = self,
.super_class = class_isMetaClass(object_getClass(self)) //check if we are an instance or Class
? object_getClass(class) //if we are a Class, we need to send our metaclass (our Class's Class)
: class //if we are an instance, we need to send our Class (which we already have)
};
id (*objc_superAllocTyped)(struct objc_super *, SEL) = (void *)&objc_msgSendSuper; //cast our pointer so the compiler can sort out the ABI
return (*objc_superAllocTyped)(&mySuper, selector);
}
so
[self performSelector:#selector(dealloc) asClass:[self superclass]];
would be equivalent to
[super dealloc];
Carry on runtime explorers! Don't let the naysayers drag you into their land of handwaving and black magik boxes, it's hard to make uncompromisingly awesome programs there*.
*Please enjoy the Objective-C runtime responsibly. Consult with your QA team for any bugs lasting more than four hours.

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

[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?

Dynamic method creation in Objective-C

In the book The Pragmatic Programmer, the authors suggest that all method inputs should be validated. This allows problems with a method to be caught early and their sources traced easily.
In my Mac application, I accomplished this by creating an Assert class. This class has several class methods. These methods determine if some precondition is met, and if it is not, then an exception is thrown. A typical assertion might looks something like this:
-(void) setWidth: (int) theWidth {
[Assert integer: width isGreaterThanInteger: 0];
width = theWidth;
}
This works really well, and significantly reduced the amount of time I've spend bug hunting. However, I've noticed lately some of the assertion methods are very useful as predicates. For example, my integer:isGreaterThanInteger:andLessThanInteger: and my stringIsNotEmpty: methods are equally useful. To this end, I created a second class Predicate, which I filled with several of my more useful predicate methods. So I took the logic from the assert methods, and moved it into Predicate, and then rewrote my Assert methods like the following:
if ![Predicate predicateMethod]
throw exception
This has turned into a maintenance nightmare. If I change the name of a method name in Predicate, I must also change it in Assert to stay consistent. If I update the documentation of an Assert method, then I must do the same to a Predicate method.
Ideally, I would like the reconstruct the Assert class so that when any method is called on it, it intercepts the selector. The Predicate class can then be checked to see if it responds to the selector, and if it does, the method is called on Predicatewith the same arguments that were passed into the Assert method. If the Predicate method returns false, then an exception is thrown.
Is there a way to do this in Objective-C?
Thanks.
You could use -forwardingTargetForSelector: to simply forward the method to another object, but if you want advanced behavior (like checking the return value to see if it's false), you may need to use -forwardInvocation:. (However, note that the documentation says this is "much more expensive" than the former option.)
If you're using pure Objective-C, you should see the "Forwarding" discussion here. It basically describes how to do exactly what you want, including example code.
If you're using Cocoa then you might have to use forwardInvocation: instead.
I ended up overriding resolveClassMethod:. While overriding forwardInvocation might have worked (I would have had to figure out some way to override it for the class object), resolveClassMethod: seems like it's the easier and more efficient method. Here's what my final implementation ended up looking like:
#import "Assert.h"
#import "Predicate.h"
#include <objc/objc-runtime.h>
void handlePredicateSelector(id self, SEL _cmd, ...);
#implementation Assert
+(void) failWithMessage: (NSString *) message
{
NSLog(#"%#", message);
[NSException raise:#"ASSERTION FAILURE" format:message];
}
+(void) fail
{
[Assert failWithMessage:#"An unconditional failure has been detected."];
}
+(BOOL) resolveClassMethod: (SEL) selector
{
if ([(id) [Predicate class] respondsToSelector:selector])
{
/*
The meta class fix was taken from here: http://iphonedevelopment.blogspot.com/2008/08/dynamically-adding-class-objects.html
*/
//get the method properties from the Predicate class
Class predicateMetaClass = objc_getMetaClass([[Predicate className] UTF8String]);
Method predicateMethod = class_getClassMethod(predicateMetaClass, selector);
const char *encoding = method_getTypeEncoding(predicateMethod);
Class selfMetaClass = objc_getMetaClass([[self className] UTF8String]);
class_addMethod(selfMetaClass, selector, (IMP) handlePredicateSelector, "B#:?");
return YES;
}
return [super resolveClassMethod:selector];
}
#end
void handlePredicateSelector(id self, SEL _cmd, ...)
{
//get the number of arguments minus the self and _cmd arguments
NSMethodSignature *predicateMethodSignature = [(id) [Predicate class] methodSignatureForSelector:_cmd];
NSUInteger numberOfArguments = [predicateMethodSignature numberOfArguments] - 2;
NSInvocation *predicateInvocation = [NSInvocation invocationWithMethodSignature:predicateMethodSignature];
[predicateInvocation setTarget:[Predicate class]];
[predicateInvocation setSelector:_cmd];
va_list ap;
va_start(ap, _cmd);
for (int i = 0; i < numberOfArguments; i++)
{
void *arg = va_arg(ap, void *);
[predicateInvocation setArgument:&arg atIndex:i+2];
}
va_end(ap);
BOOL returnValue;
[predicateInvocation invoke];
[predicateInvocation getReturnValue:&returnValue];
//determine if the assertion is true
if (!returnValue)
{
[Assert failWithMessage:[NSString stringWithFormat: #"The following assertion failed: %#", NSStringFromSelector(_cmd)]];
}
}
The only thing I couldn't really figure out was how to get the type encoding from the method signature. It didn't seem to affect the output of the methods, but I would like to fix it if I can.