Objective C reflection for C-type vars - objective-c

I have few extern variables declared in #interface block of my .h file. They are assigned in .m file. In one method of my #interface (preferable class method) I want to enumerate over these variables via reflection, but I have no any idea is it possible at all, and how is yes ?
Example of my code:
Consts.h
extern NSString *MyConst1;
extern NSString *MyConst2;
Consts.m
NSString *MyConst1 = nil;
NSString *MyConst2 = nil;
+ (void)load {
MyConst1 = ...;
MyConst2 = ...;
}
+ (void)someMethod {
// i could use class_copyIvarList for objective c properties/ivars,
// but is it possible to get that MyConts1 and MyConst2 via reflection ?
// I understand, that C have different namespace,
// and I have no experience with it.
}

Objective-C supports reflection for Objective-C objects. The reflection works because every Obj-C class contains the necessary metadata (property names, method names etc.).
Objective-C doesn't in any way change the C language. Objective-C runtime is basically implemented in C and the compiler only translates Objective-C into C function calls.
No, you cannot use reflection for global variables outside the context of any Objective-C class.
If you want reflection, wrap them into a class.
However, note, that using reflection is almost never a good solution. Usually it is abused to solve a problem that is caused by bad architecture.

There are no class variables in ObjC. Only instances can have variables in ObjC. Even if you declare a global between #interface or #implementation and #end, it will still just be a global, ObjC doesn't actually know about it.
Only the ObjC parts in a .m file support introspection. One alternative approach would be to create a singleton that has methods returning your constants, then you can enumerate its methods. Alternately, you could create a function/method that returns an array of your constants. To avoid duplication of your constants and array, you could use the X Macro technique:
#define OSC_TYPE_CONSTANTS X(MyConst1) \
X(MyConst2)
// Header:
#define X(n) extern NSString* n;
OSC_TYPE_CONSTANTS
#undef X
// Implementation:
#define OSC_STRINGIFY(n) #n
#define X(n) NSString* n = OSC_STRINGIFY(n);
OSC_TYPE_CONSTANTS
#undef X
#define X(n) n,
NSArray* gAllTypesArray = [NSArray arrayWithObjects: OSC_TYPE_CONSTANTS nil];
#undef X
What do you need this for? Are these constants compiled directly into your app, or is this in a framework from which they are exported? Depending on that, there may be solutions involving CFBundle's CFBundleGetDataPointerFromName or dlsym.

Related

Accessing static variables that are simulating class variables from unit tests

Is there an Objective-C runtime library function (unlikely) or set of functions capable of inspecting static (quasi-class level) variables in Objective-C? I know I can utilize a class accessor method but I'd like to be able to test without writing my code "for the test framework".
Or, is there a obscure plain C technique for external access to static vars? Note this information is for unit testing purposes—it needn't be suitable for production use. I'm conscious that this'd go against the intent of static vars... a colleague broached this topic and I'm always interested in digging into ObjC/C internals.
#interface Foo : NSObject
+ (void)doSomething;
#end
#implementation Foo
static BOOL bar;
+ (void)doSomething
{
//do something with bar
}
#end
Given the above can I use the runtime library or other C interface to inspect bar? Static variables are a C construct, perhaps there's specific zone of memory for static vars? I'm interested in other constructs that may simulate class variables in ObjC and can be tested as well.
No, not really, unless you are exposing that static variable via some class method or other. You could provide a + (BOOL)validateBar method which does whatever checking you require and then call that from your test framework.
Also that isn't an Objective-C variable, but rather a C variable, so I doubt there is anything in the Objective-C Runtime that can help.
The short answer is that accessing a static variable from another file isn't possible. This is exactly the same problem as trying to refer to a function-local variable from somewhere else; the name just isn't available. In C, there are three stages of "visibility" for objects*, which is referred to as "linkage": external (global), internal (restricted to a single "translation unit" -- loosely, a single file), and "no" (function-local). When you declare the variable as static, it's given internal linkage; no other file can access it by name. You have to make an accessor function of some kind to expose it.
The extended answer is that, since there is some ObjC runtime library trickery that we can do anyways to simulate class-level variables, we can make make somewhat generalized test-only code that you can conditionally compile. It's not particularly straightforward, though.
Before we even start, I will note that this still requires an individualized implementation of one method; there's no way around that because of the restrictions of linkage.
Step one, declare methods, one for set up and then a set for valueForKey:-like access:
// ClassVariablesExposer.h
#if UNIT_TESTING
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#define ASSOC_OBJ_BY_NAME(v) objc_setAssociatedObject(self, #v, v, OBJC_ASSOCIATION_ASSIGN)
// Store POD types by wrapping their address; then the getter can access the
// up-to-date value.
#define ASSOC_BOOL_BY_NAME(b) NSValue * val = [NSValue valueWithPointer:&b];\
objc_setAssociatedObject(self, #b, val, OBJC_ASSOCIATION_RETAIN)
#interface NSObject (ClassVariablesExposer)
+ (void)associateClassVariablesByName;
+ (id)classValueForName:(char *)name;
+ (BOOL)classBOOLForName:(char *)name;
#end
#endif /* UNIT_TESTING */
These methods semantically are more like a protocol than a category. The first method has to be overridden in every subclass because the variables you want to associate will of course be different, and because of the linkage problem. The actual call to objc_setAssociatedObject() where you refer to the variable must be in the file where the variable is declared.
Putting this method into a protocol, however, would require an extra header for your class, because although the implementation of the protocol method has to go in the main implementation file, ARC and your unit tests need to see the declaration that your class conforms to the protocol. Cumbersome. You can of course make this NSObject category conform to the protocol, but then you need a stub anyways to avoid an "incomplete implementation" warning. I did each of these things while developing this solution, and decided they were unnecessary.
The second set, the accessors, work very well as category methods because they just look like this:
// ClassVariablesExposer.m
#import "ClassVariablesExposer.h"
#if UNIT_TESTING
#implementation NSObject (ClassVariablesExposer)
+ (void)associateClassVariablesByName
{
// Stub to prevent warning about incomplete implementation.
}
+ (id)classValueForName:(char *)name
{
return objc_getAssociatedObject(self, name);
}
+ (BOOL)classBOOLForName:(char *)name
{
NSValue * v = [self classValueForName:name];
BOOL * vp = [v pointerValue];
return *vp;
}
#end
#endif /* UNIT_TESTING */
Completely general, though their successful use does depend on your employment of the macros from above.
Next, define your class, overriding that set up method to capture your class variables:
// Milliner.h
#import <Foundation/Foundation.h>
#interface Milliner : NSObject
// Just for demonstration that the BOOL storage works.
+ (void)flipWaterproof;
#end
// Milliner.m
#import "Milliner.h"
#if UNIT_TESTING
#import "ClassVariablesExposer.h"
#endif /* UNIT_TESTING */
#implementation Milliner
static NSString * featherType;
static BOOL waterproof;
+(void)initialize
{
featherType = #"chicken hawk";
waterproof = YES;
}
// Just for demonstration that the BOOL storage works.
+ (void)flipWaterproof
{
waterproof = !waterproof;
}
#if UNIT_TESTING
+ (void)associateClassVariablesByName
{
ASSOC_OBJ_BY_NAME(featherType);
ASSOC_BOOL_BY_NAME(waterproof);
}
#endif /* UNIT_TESTING */
#end
Make sure that your unit test file imports the header for the category. A simple demonstration of this functionality:
#import <Foundation/Foundation.h>
#import "Milliner.h"
#import "ClassVariablesExposer.h"
#define BOOLToNSString(b) (b) ? #"YES" : #"NO"
int main(int argc, const char * argv[])
{
#autoreleasepool {
[Milliner associateClassVariablesByName];
NSString * actualFeatherType = [Milliner classValueForName:"featherType"];
NSLog(#"Assert [[Milliner featherType] isEqualToString:#\"chicken hawk\"]: %#", BOOLToNSString([actualFeatherType isEqualToString:#"chicken hawk"]));
// Since we got a pointer to the BOOL, this does track its value.
NSLog(#"%#", BOOLToNSString([Milliner classBOOLForName:"waterproof"]));
[Milliner flipWaterproof];
NSLog(#"%#", BOOLToNSString([Milliner classBOOLForName:"waterproof"]));
}
return 0;
}
I've put the project up on GitHub: https://github.com/woolsweater/ExposingClassVariablesForTesting
One further caveat is that each POD type you want to be able to access will require its own method: classIntForName:, classCharForName:, etc.
Although this works and I always enjoy monkeying around with ObjC, I think it may simply be too clever by half; if you've only got one or two of these class variables, the simplest proposition is just to conditionally compile accessors for them (make an Xcode code snippet). My code here will probably only save you time and effort if you've got lots of variables in one class.
Still, maybe you can get some use out of it. I hope it was a fun read, at least.
*Meaning just "thing that is known to the linker" -- function, variable, structure, etc. -- not in the ObjC or C++ senses.

Is there a way to wrap protocol buffers into Objective-C and still take advantage of inheritance?

I want to use Protocol Buffers in an iOS project. I'm trying to avoid making the whole project into an Objective-C++ fiasco, so I want to wrap the C++ protobuf classes into Objective-C ones. I have several dozen protobuf messages, and while I have done this successfully one class at a time, ideally I would like to use inheritance to minimize the repeated code. I'm new to Objective-C and I haven't used what little I knew of C++ in 10 years, so this has mostly been an exercise in frustration. Below is an example of how I have wrapped a single message.
Code
.proto:
message MessageA {
optional string value = 1;
}
MessageAWrapper.h:
#import <Foundation/Foundation.h>
#interface MessageAWrapper : NSObject
#property (nonatomic) NSString *value;
+ (id)fromString:(NSString *)string;
- (NSString *)serialize;
#end
MessageAWrapper.mm:
#import "MessageA.h"
#import "message.pb.h"
#interface MessageAWrapper ()
#property (nonatomic) MessageA *message;
#end
#implementation MessageAWrapper
- (id)init
{
self = [super init];
if (self) {
self.message = new MessageA();
}
return self;
}
- (void)dealloc {
delete self.message;
self.message = NULL;
}
- (NSString *)value {
return [NSString stringWithUTF8String:self.message->value().c_str()];
}
- (void)setValue:(NSString *)value {
self.message->set_value([value UTF8String]);
}
- (NSString *)serialize {
std::string output;
self.message->SerializeToString(&output);
return [NSString stringWithUTF8String:output.c_str()];
}
+ (id)fromString:(NSString *)string {
MessageA *message = new MessageA();
message->ParseFromString([string UTF8String]);
MessageAWrapper *wrapper = [[MessageAWrapper alloc] init];
wrapper.message = message;
return wrapper;
}
#end
Goal
There is a lot of code here that will be repeated dozens of times in which the only variation is the wrapped class type (init, dealloc, serialize, fromString), so ideally I would like to put it on a parent ProtobufMesssage class instead. Unfortunately I've had no success in making this work because I can't find a way for the parent class to know the class its children are using, which is required for example in init and fromString.
Things I've attempted
struct
template class
void*
Obstacles I've encountered
can't find a way to store a reference to a class/type
can't have any C++ headers or code in the .h file (as this requires the whole project to be Objective-C++)
difficulty keeping references to the protobuf message parents (Message or MessageLite) because they are abstract
As I said I have very little understanding of C++ or Objective-C; most of my experience is with much higher level languages like Python and Java (though I do mostly understand basic C things like pointers).
Is this perhaps not even possible? Am I approaching it wrong or missing something obvious? Any help would be much appreciated. Thanks.
I don't know much about C++ at all, but can't you declare the Objective-C property to be a Message *?
You've already separated the C++ code from the header by declaring the property in the .mm file, the problem you will have is with instance methods named by the compiler (value() and set_value()) and only being valid methods for the subclass. It might help to use the Reflection class to get and set fields by their name. Here is an excerpt from Google's message.h showing this:
Message* foo = new Foo;
const Descriptor* descriptor = foo->GetDescriptor();
const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
assert(text_field != NULL);
assert(text_field->type() == FieldDescriptor::TYPE_STRING);
assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
const Reflection* reflection = foo->GetReflection();
assert(reflection->GetString(foo, text_field) == "Hello World!");
You could create Objective-C -objectForKey: and -setObject:forKey: instance methods that typecheck and get or set the value (confusingly, the key in the case of MessageAWrapper would be #"value"). Your subclasses would not even need to be aware of the C++ code.
You can also separate the creator function in -init and +fromString: method into something like, +_createNewInstance;
+(Message*)_createNewInstance{ return new MessageA(); }
allowing your subclasses of MessageWrapper to reuse all code except for creating the C++ object.
While Objective C has very powerful instrospection capabilities, C++ is more limited. You do have RTTI (Run time type information), but it's not even as powerful as the Objective C counterpart.
However, it might be enough for you. Within your Objective C++ class, you might find the type of you message object with the typeid operator:
if( (typeid(self.message) == typed(foo)){
//doSomething
else if( (typeid(self.message) == typed(bar)){
// doSomething else
}
Maybe the best option is to add another indirection level. Make an Objective C class hierarchy that wraps all your protocol buffer C++ classes and then create another Objective C that uses those classes (as delegates maybe). I believe this might be a better option. Use C++ only for those unavoidable cases.
Good luck!

Can the new Clang Objective-C literals be redirected to custom classes?

Although the overloading of # begins to tread on dangerous territory, I love the addition of the new Objective-C literals in Clang 3.1. Unfortunately the new literals are of limited use to me. Except for instances where code needs to interface with AppKit, I've mostly dropped the use of Foundation classes in favor of my own custom framework (for a variety of reasons; most of which is that I need direct control over the memory allocation patterns used by objects).
I could always use some runtime trickery to pass off the newly created object as my custom class (and is what I already have to do with string object literals, since only the non-Apple GCC runtime supports the -fconstantstring=class flag), but this is a hack at best and throws out all the benefits I gained by replacing the equivalent Foundation class to begin with.
Unlike string object literals, the new literals Clang implements are not actually constant classes (where the memory layout is hardcoded); instead the appropriate messages are sent to their respective classes to create and initialize a new object at runtime. The effect is no different than if you had created the object yourself. In theory it means that the classes used and the methods called by the new literals are not hardcoded. In practice I can't find any way to change them to point to my own custom classes and methods (I would in fact be happy just to point to a custom class; pointing a dummy method to an actual method at runtime isn't difficult).
When I first looked into this, I was really hoping to find a set of flags that could be used to do what I'm asking, but as I haven't found any, I'm hoping someone has a solution.
You can substitute class for some Objective-C literals with #compatibility_alias keyword trick.
Here's an example.
#compatibility_alias NSNumber AAA;
Of course, you should provide proper implementation for new class.
#import <Foundation/NSObject.h>
#interface AAA : NSObject
+ (id)numberWithInt:(int)num;
#end
#implementation AAA
+ (id)numberWithInt:(int)num
{
return #"AAAAA!!!"; // Abused type system just to check result.
}
#end
#compatibility_alias NSNumber AAA;
Now Clang will do the job for you. I confirmed this is working for number, array, dictionary literals. Unfortunately string literals seem to be emitted statically, so it won't work.
For more information about #compatibility_alias keyword, see here.
Note
Because #compatibility_alias keyword is a compiler directive which applies to current compilation unit, you need to separate compilation unit to avoid symbol duplication with NSObject class in Apple's Foundation Kit. Here's how I did it.
main.m
#import "test.h" // Comes before Foundation Kit.
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool
{
NSLog(#"return of test = %#", test());
// insert code here...
NSLog(#"Hello, World!");
}
return 0;
}
test.h
id test();
test.m
#import "test.h"
#import <Foundation/NSObject.h>
#interface
AAA : NSObject
+ (id)numberWithInt:(int)v;
+ (id)arrayWithObjects:(id*)pobj count:(int)c;
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c;
#end
#implementation AAA
+ (id)numberWithInt:(int)v
{
return #"AAAAA as number!!!";
}
+ (id)arrayWithObjects:(id*)pobj count:(int)c
{
return #"AAAAA as array!!!";
}
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c
{
return #"AAAAA as dictionary!!!";
}
#end
#compatibility_alias NSDictionary AAA;
#compatibility_alias NSArray AAA;
#compatibility_alias NSNumber AAA;
id test()
{
// return #{};
// return #[];
return #55;
}
Result.
2013-03-23 08:54:42.793 return of test = AAAAA!!!
2013-03-23 08:54:42.796 Hello, World!
The comments have it all correct, but just to summarize:
No.
The meanings of Apple's #{}, #[], and #"" literals are hard-coded into Clang. You can see it here: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?view=markup It's all fairly modular, meaning that it wouldn't be hard for a Clang hacker to add her own literal syntax... but "modular" doesn't mean "accessible from the outside". Adding a new syntax or even redirecting the existing syntax to new classes would definitely require rebuilding Clang yourself.
Here's a blog post about adding NSURL literals to Clang by hacking on its internals: http://www.stuartcarnie.com/2012/06/llvm-clang-hacking-part-3.html (Thanks #Josh Caswell)
If you're willing to use Objective-C++ with C++11 extensions, you can has "user-defined literals", which allow you to write things like
NSURL *operator ""URL (const char *s) { return [NSURL URLWithString: #(s)]; }
int main() {
...
NSURL *myurl = "ftp://foo"URL;
...
}
This was mentioned in the comments on Mike Ash's blog. http://www.mikeash.com/pyblog/friday-qa-2012-06-22-objective-c-literals.html But this doesn't look very Objective-C-ish (or very C++ish!), and it works only with an Objective-C++11 compiler, and in general please don't do this. :)

declare obj-c class interface that contain c++ class type ivar

Currently I am working on a cocos2d+Box2D project so I have deal with some Objective-C++ code.
And I am facing to such situation:
#import "cocos2d.h"
#import "Box2D.h"
#interface BasicNode : CCNode {
#private
ccColor3B _color;
b2Body *_body;
b2Fixture *_shape;
}
b2Body and b2Fixture are C++ class that defined in Box2D.h
It works if the implementation of BasicNode is named BasicNode.mm.
But if I have another file named Game.m that is using BasicNode and import BasicNode.h, it won't compile because .m file is Obj-C file and does not know about C++ code.
So I decided to move #import "Box2D.h" into implementation file and only keep type declaration in head file (this is exactly what header file should contain).
But how do I do it? They are C++ class type but they are actually just a pointer so I wrote some helper macro
#ifdef __cplusplus
#define CLS_DEF(clsname) class clsname
#else
#define CLS_DEF(clsname) struct clsname; typedef struct clsname clsname
#endif
CLS_DEF(b2Body);
CLS_DEF(b2Fixture);
It works, only if CLS_DEF(b2Body) is appear once only. Otherwise compiler will find multiple type declaration for a same name even they are the same. Than I have to change to
#ifdef __cplusplus
#define CLS_DEF(clsname) class clsname
#else
#define CLS_DEF(clsname) #class clsname
#endif
And it is working now.
But I don't think it is a great idea that I declare a C++ class type as an Obj-C class especially I am using ARC.
Is any better way do deal with it? And I don't really want to make something like this
#interface BasicNode : CCNode {
#private
ccColor3B _color;
#ifdef __cplusplus
b2Body *_body;
b2Fixture *_shape;
#else
void *_body;
void *_shape;
#endif
}
Edit: Also please tell me will my tweak way introduce any problem?? by making C++ class ivar looks like Obj-C class for other pure Obj-C code.
One simple solution is to rename Game.m to Game.mm.
There are a couple of ways. If you can rely on using the Objective-C 2.2 runtime's features, you can add ivars in class (category) extensions. This means you can add ivars in your class's .mm file, and keep the .h file clean of any C++ stuff.
If you need to support older versions of the runtime, there are a few ways to do it which are better than #ifdefing. In my opinion, the best way is to use the 'pimpl' idiom which is common in C++ - you forward declare an implementation struct in your header, and add an ivar which is a pointer to such a struct. In your class's implementation (.mm), you actually define that struct with all its C++ members. You then just need to allocate that implementation object in your init... method(s) with new and delete it in dealloc.
I've written up the pimpl idiom as it applies to cleanly mixing Objective-C and C++ in this article - it also shows some other potential solutions which you could consider.
With Xcode 5, you don't have to declare instance variables in the header file, you can just declare them in the implementation file. So your BasicNode header file is not "contaminated" with C++.
You can use "struct" instead of "class" in C++. The only difference is that in a class all members are private by default, while in a struct they are public by default. But you can do everything with a struct that you can do with a class. That way you can write for example
struct b2Body;
struct b2Fixture;
outside your interface, and
{ ...
struct b2Body* _body;
...
}
in your interface.

Objective-C Clarification; -/+ and *var

I'm teaching myself Objective-C from a book (Cocoa programming for mac OS X) and am about halfway through however I have two questions that aren't answered or defined in the book.
When defining class methods what is the difference between (assuming there in a .h file):
- (int) population;
+ (int) population;
The way I see it at the moment is that - methods require the class to be allocated and initialized first however + can be called statically without requiring allocation and initialization. E.g. (in a function in another class)
// Using -
Earth *world = [[Earth alloc] init];
int population = [world population];
// Using +
int population = [Earth population];
If that is correct, when should I use static methods and are they're any disadvantages with doing so.
When defining a var in either a function paramater or as an actual var in a function, does the use of * mean the var will be an object? e.g. (again in a header file.)
- (void) setPopulation: (NSNumber *) population; //Use of * as population is of NSNumber
- (void) setPopulation: (int) population; // population isn't a class so doesn't need *
Sorry if any of my terms don't make sense in the land of Objective-C such as static methods, etc. I'm a PHP and Ruby Programmer.
The -/+ in method declarations for Objective-C simply denote whether the method is a class method or an instance method. For example, with Objective-C, you cannot send an instance a message that was declared as a class method. For example:
#interface MyObject : NSObject
-(void)myInstanceMethod;
+(void)myClassMethod;
#end
// ...
MyObject* obj = [[MyObject alloc] init];
[obj myInstanceMethod]; // this is okay
[obj myClassMethod]; // this will fail
[[obj class] myClassMethod]; // this is okay
[MyObject myClassMethod]; // this is okay
[MyObject myInstanceMethod]; // this will fail
As to the second part of your question, Objective-C is a strict super-set of C. It adds classes but they are really C data structures whose implementations are hidden from you by the Objective-C runtime. Because of this, classes are always represented as pointers. In C, the * means that the variable is being declared as a pointer to some memory address. You can use pointers with primitive types in C as well, but Objective-C objects must always be referred to by pointers.
There are many great tutorials/introductions to pointers out there. I would suggest simply googling for C tutorial and pointers to learn more.
The + declaration is a class method, you need no instance to call it. Constructors/factory methods need to be class methods. The - declared an instance method, operation on a single instance. Each instance has its own independent state (member variables). This is a fundamental difference in OO programming! In general make most methods instance methods, except for utility classes.
You can see some discussion of when to use static methods in When should I write Static Methods?