Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the Objective-C class of an ivar?

I have a bunch of simple NSManagedObjects I create in a unit test. They just have a single name attribute of type NSString *. I always give my NSManagedObject the same entityName and Class name.

I want to avoid having to write the following code 30 times to set up a unit test:

@interface FooTest : GHTestCase {
Foo *foo;
}
@end
@implementation FooTest

- (void) setUp {
  [super setUp];

  foo = [NSEntityDescription insertNewObjectForEntityForName:@"Foo"
                                      inManagedObjectContext:managedObjectContext];
  foo.name = @"foo";
}
@end

Since foo is an ivar, I would think I should be able to write a macro to grab the type of foo (Foo), and use to create my Foo:

#define InsertManagedObjectByVariable(variable) \
do { \
variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])]; \
variable.name = (NSString *) CFSTR(#variable);
} while(0)

However, this causes the following warning in clang:

variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])];
                                                                               ^
                                                             Expected expression

I also thought I could try to determine the type using the objective-c runtime IVar from Ivar class_getInstanceVariable(Class cls, const char* name), but the only IVar type information available from the type encoding from ivar_getTypeEncoding is id, which isn't enough.

Can someone think of a way to obtain the type information of an IVar either at compile time or runtime?

like image 332
Heath Borders Avatar asked Jun 29 '12 16:06

Heath Borders


2 Answers

I haven't tried obtaining class information from an ivar, but I know that @property declarations do encode information about the class. For instance, this property declaration:

@property (copy) NSString *normalString;

results in this attribute string (retrieved using property_getAttributes()) at runtime:

T@"NSString",C,VnormalString

I've written some open source parsing code for this information.

Once you have the class name, you can convert it into an actual Class object using NSClassFromString(), and message the result from there.

Disclaimer: This probably shouldn't be depended upon for production applications, as it is undocumented.

like image 189
Justin Spahr-Summers Avatar answered Nov 18 '22 11:11

Justin Spahr-Summers


An id is an id. At runtime, all Objective-C objects have the same type (objc_object). This is tied up in the dynamic nature of ObjC. For example, an object can change classes at runtime, new classes can be created, and the class hierarchy can change. You can ask a specific instance what its type is (since this is stored in objc_object), but a pointer to an object is just a pointer to an object. Even less than that: it's really just a pointer to a C struct that happens to have extra memory allocated at the end (to hold subclass ivars).

Your macro seems interesting, but you'll probably need to pass the classname as the second parameter rather than autodetecting it.

like image 5
Rob Napier Avatar answered Nov 18 '22 10:11

Rob Napier