How to get classname in objective c Like 'NSString' - objective-c

I want to get the class name of an object as what we are using.
That means now if I write this code
NSString *s = [NSString string];
NSLog(#"%#",[s class]);
The output is __NSCFConstantString
How can I get it as NSString itself ?
Note : NSString is just an example
I know __NSCFConstantString is correct. But my intention is to get like NSString. Is there any way to acheive this?

Give these a try, they'll output NSString. Keep in mind, the second set requires importing the Objective-C runtime header.
#import <objc/runtime.h>
NSString *string = #"I'm a string.";
NSLog(#"%#",NSStringFromClass([string classForCoder]));
NSLog(#"%#",NSStringFromClass([string classForKeyedArchiver]));
NSLog(#"%s",class_getName([string classForCoder]));
NSLog(#"%s",class_getName([string classForKeyedArchiver]));
Now, this won't work in all cases. For example, trying to get the class of NSConstantString, in this manner will output NSString. If you require checking the class name as a string in this way, you probably should reconsider your approach to solving the problem.

NSString is a so-called "class cluster". That means that the init methods will return
an instance of some subclass (such as __NSCFConstantString or __NSCFString).
You will never get an instance with the class equal to NSString.
If your intention is to check whether an object is a NSString or not then
use isKindOfClass:
if ([s isKindOfClass:[NSString class]]) {
// this is a string …
}
Other examples of class clusters are NSNumber, NSDictionary, NSArray
and their mutable variants.

NSLog(#"%#", NSStringFromClass([s class]));

Related

Constant value of NSString representation

I have a PList where I load a couple of rows of data in a dictionary. I want to add the a line like
<key>StandardValue</key>
<string>STANDARDVALUEFORCERTAININSTANCE</string>
Now when I read out the values I get a NSString. How can I get the value of the constant that I previously defined with
#define STANDARDVALUEFORCERTAININSTANCE 123
Is there a way to get the constant representation of a string? So essentially to parse it?
What you want to do isn't exactly possible. The constants created with #define only exist at compile-time, and at run time there is no way to access them by name - they have been converted to the constant value already.
One alternative that might exist is to define a number of methods that return constant values, say in a Constants class. Then, at run time, load the name of the method from the plist and call it using NSSelectorFromString() and performSelector:.
However, a possible issue with this is that for safety with performSelector: you'd have to rewrite all your constants as Objective-C objects (since performSelector: returns type id). That could be quite inconvenient.
Nevertheless, here is an example implementation of the Constants class:
#implementation Constants : NSObject
+ (NSNumber *)someValueForACertainInstance
{
return #123;
}
#end
And example usage:
NSDictionary *infoDotPlist = [[NSBundle mainBundle] infoDictionary];
NSString *selectorName = infoDotPlist[#"StandardValue"];
SEL selector = NSSelectorFromString(selectorName);
NSNumber *result = [Constants performSelector:selector];
And how the selector name would be stored in the info plist:
<key>StandardValue</key>
<string>someValueForACertainInstance</string>
You can't do it this way. I suggest a nice alternative: KVC.
You declare this variable as class instance:
#property (nonatomic,assign) int standardValueForCertainInstance;
Then you get the value with valueForKey:
NSString* key= dict[#"StandardValue"];
int value= [[self valueForKey: key] intValue];

Why NSDecimalNumber in a NSString?

I have an object that got parsed into an NSString and when I trace out the class name, it says NCDecimalNumber. Why? (I understand NSString is a cluster, but still don't understand why NSDecimalNumber would be a part of what's behind the cluster)
The following post asks a similar question but no one answers the why.
Converting NSDecimalNumber to NSString
This sounds like the decoder decodes the number into an NSDecimalNumber (and strings into NSStrings).
Remember, Objective-C is C, so you can effectively assign anything to a pointer, it is up to you to ensure that the types correspond. This is why you can assign an object of type NSNumber to a pointer declared to be of type NSString*. As you can see, class clusters don't have anything to do with this.
So before assigning your object to a variable, you should check the class or, alternatively, just assign the object to a pointer of type id (which can hold any object).
If you need to work on the objects based on their type, you can do something like this:
id obj = //...
if ( [obj isKindOfClass: [NSString class]] ) {
}
else if ( [obj isKindOfClass: [NSNumber class]] ) {
}
else {
}
Try to use this:
NSString *string = [[NSStrig alloc] initWithFormat:#"%#", [DecimalNumber stringValue]];
Hope that is going to help you.

Basic Objective-C typecasting question

Consider the following code:
if([obj isKindOfClass:[NSString class]]) {
NSString *s = [(NSString *)obj stringByAppendingString:#"xyzzy"];
}
I'm a bit confused here. The if statement checks whether or not obj is of the NSString class. If it is, it assigns the object and an appended string to NSString *s, do I understand this correctly? If so, why would you still cast it to (NSString *)?
Doesn't the if statement already check for that and doesn't that make the typecasting unnecessary?
Wouldn't it be perfectly fine to just say:
NSString *s = obj stringByAppendingString:#"xyzzy"];
Thanks in advance.
It all depends on how obj is defined. If it is id obj then no casting is needed, but if it was defined as NSObject *obj the cast is necessary to suppress the compiler warning that stringByAppendingString: is not defined on NSObject. The cast is not needed to make the code work at runtime, it only tells the compiler the "correct" type so it can tell whether the method should exist on the object.
The reason why the cast isn't needed for id is because id means "an object of any type", while NSObject * means "an object of type NSObject".

what is this weird code notation mean

what's this line mean when using the second NSDictionay beside the message body:
NSDictionary *item = (NSDictionary *) [self.content objectAtIndex:indexPath.row];
(NSDictionary *) a type cast. It tells the compiler to assume that the object returned by the objectAtIndex: method is of the type NSDictionary * even though the return type of the method is different.
self.content is a property of type NSArray (I guess!)
This line returns you the Object (which seams to be a NSDictionary) at Index indexPath.row. (NSDictionary*) casts the object to NSDictionary.
This is a cast, as in C.
In your case, "self.content" seems to be an NSArray. So [self.content objectAtIndex:indexPath.row] would be an NSObject. Except that here, for some reason, you know it's an NSDictionary. So you explicitly cast it in order to avoid a compiler warning (that would tell you "hey, you're assigning an NSObject to an NSDictionary variable)

How do I get class information at runtime in Objective-C?

I have NSMutableArray with different objects in it of different classes. Now I want to get the class name, related stuff and also check if the respective object is NSString or not. How should I go about it?
I was trying something like the following. It wasn't working of course.
for(NSString *string in array){
NSLog(#"Name of the class : %#", [NSString stringWithCString:class_getName(Class id)];
If you're on Mac OS X, you can use [object className], it returns an NSString
for(id obj in array) NSLog(#"Name of the class: %#", [obj className]);
To check if it's a NSString, you should use something like this:
for(id obj in array) {
if ([obj isKindofClass:[NSString class]]) {
// do something
}
}
for(id object in array){
NSLog(#"Name of the class: %#", [object className]);
NSLog(#"Object is a string: %d", [object isKindOfClass:[NSString class]]);
}
Take a look at the NSObject class and protocol for other interesting methods.
I have NSMutableArray with different objects in it of different classes. Now I want to get the class name & related stuff & also check if the respective object is NSString or not.
Hold up. Why do have an array of different typed objects in the first place? Could you redo your design to avoid getting into that situation?
As others have said, -isKindOfClass: works. One downside is it generally leads to brittle code. Here your loop needs to know about all the classes that could be in the array. Sometimes this is the best you can do though.
Designs that use -respondsToSelector: tend to be a little more robust. Here your loop would need to know about the behaviors it depends on of classes in the array.