3

I am building my first iPhone/Obj-c app and I have a large amount of data-holding subclasses that I am passing into a cite function. To the cite function these objects are anonymous and I need to find a way to access all the variables of each passed object. I have been using a pre-built NSArray and Selectors to do this but with more than 30 entries (and growing) it is kind of silly to do manually. There has to be a way to dynamically look up all the variables of an anonymous object.

The obj-c runtime run-time docs mention this problem but from what I can tell this is not available in iPhone OS. If it is then I don't understand the implementation and need some guidance. A similar question was asked before but again I think they were talking about OSX and not iPhone.

Any thoughts?

-(NSString*)cite:(id)source {
 NSString *sourceClass = NSStringFromClass([source class]);

 // Runs through all the variables in the manually built methodList
 for(id method in methodList) {
  SEL x = NSSelectorFromString(method);
  // further implementation

 // Should be something like
 NSArray *methodList = [[NSArray alloc] initWithObjects:[source getVariableList]]
 for(id method in methodList) {
  SEL x = NSSelectorFromString(method);
  // Further implementation
 }
Community
  • 1
  • 1
ChrisOPeterson
  • 559
  • 1
  • 6
  • 24

2 Answers2

11

The runtime is the same on the Mac as it is on the iPhone. If the other question does what you're looking for, then it should work. If it doesn't, file a bug.

In the meantime, given a Class, you can retrieve a list of all of its selectors using the class_copyMethodList() function:

unsigned int numMethods = 0;
Method * methods = class_copyMethodList(sourceClass, &numMethods);
NSMutableArray * selectors = [NSMutableArray array];
for (int i = 0; i < numMethods; ++i) {
  SEL selector = method_getName(methods[i]);
  [selectors addObject:NSStringFromSelector(selector)];
}
free(methods);
mxcl
  • 26,392
  • 12
  • 99
  • 98
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • The way you implemented this was almost exactly how I imagined but I missed the most simplistic thing which was the #import at the top. I just assumed that this was global and that the methods were invalid because of another issue. Doh. So I got this working but another problem presents itself. This only lists the methods implemented by the current class and not any superclass methods. I guess I am going to have to loop through all the classes, fun. Thanks. – ChrisOPeterson May 25 '10 at 00:37
  • @Chris yep, superclass methods must be discovered in the same manner. :) – Dave DeLong May 25 '10 at 01:21
5

It's certainly possible to do this through the Objective-C runtime functions, but it's probably not the right way to go about it. Since you're creating the objects passed into the cite method, just have them each implement a protocol that cite can use to extract whatever information it needs.

Something like the Key-Value Coding protocol will probably do what you want: http://developer.apple.com/iphone/library/documentation/cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html

Mark Bessey
  • 19,598
  • 4
  • 47
  • 69
  • I agree with this. If the objects are passed interchangeably, they should implement a common interface. This is one of the great strengths of Objective-C's dynamic OO system. – Chuck May 24 '10 at 21:09
  • After looking through a bunch of KVC and Protocol tutorials I am a little confused as to either would help, KVC in particular. Your Protocol idea I like but how would I use it in this case? Would I return an NSArray of all the iVars? If this is the case then wouldn't I be back to using the runtime in each class' implementation of the protocol? I am creating the objects and know what is in them but I would like to build it as if I didn't know. Having the cite function ask the class what iVars it has seems like the right way to go, but i am new to objc and cocoa and maybe there is an easier way. – ChrisOPeterson May 25 '10 at 01:19
  • It's like this: your "cite" method wants to do something to or with these objects. The purpose of a protocol is to provide a common interface for these objects to interoperate with the cite method. In general, it's considered bad style to use an object as just a bag of public properties. If you want that, then use an NSDictionary. – Mark Bessey May 25 '10 at 06:22