Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Objective-C Method Definition Internals

DZone 's Guide to

Objective-C Method Definition Internals

In a previous article we looked at class definitions and Objective C-class definition structures. Now let's look at how to use them together.

· Web Dev Zone ·
Free Resource

We've talked in a previous article about class definitions and we've looked at Objective C-class definition structures. They use an __objc_class structure which contains information with respect to the class's super class, something called a meta class, a cache, a vTable, and a pointer to class data. We were working with a simple Printer class:

#import <Foundation/Foundation.h>

@interface Printer : NSObject

@property NSString *str_to_print;

- (void) printMsg;
- (void) printString: (NSString*) message;

@end

@implementation Printer

- (void) printMsg {
printf("%s\n", [self.str_to_print UTF8String]);
}

- (void) printString: (NSString*) message {
self.str_to_print = message;
[self printMsg];
}

@end



int main(int argc, const char * argv[]) {
  @autoreleasepool {
  Printer *printer = [[Printer alloc] init];
  [printer printString: @"Hello World!"];
  }
  return 0;
}

Now a metaclass in Objective-C allows you to treat a class as an object, essentially. You can create static methods in Objective C, and the meta class is what allows you to do it. Class definitions can have associated methods and data elements, just like a class instance, and need are implememented in the same way as a result.

Coincidentally, it seems that the objc_class structure in runtime.h looks like this:

struct objc_class {
  Class _Nonnull isa OBJC_ISA_AVAILABILITY;
  #if !__OBJC2__
  Class _Nullable super_class OBJC2_UNAVAILABLE;
  const char * _Nonnull name OBJC2_UNAVAILABLE;
  long version OBJC2_UNAVAILABLE;
  long info OBJC2_UNAVAILABLE;
  long instance_size OBJC2_UNAVAILABLE;
  struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
  struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
  struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
  struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
  #endif
}

Which is not what we see when we disassemble the binary. Anyway, let's start looking through class definition we do have, we'll return to this discrepancy later.

The last element in the structure extracted from the executable was an __objc_class_Printer_data type. The other elements in the disassembled class definition ( _OBJC_METACLASS_$_PRINTER_OBJC_CLASS_s_NSObject, and __objc_empty_cache) we've either covered or they refer to data structures within the Objective-C runtime. So let's take a look at __objc_class_Printer_data:

__objc_class_Printer_data:
0000000100001198 struct __objc_data { 
  0x184, // flags
  8, // instance start
  16, // instance size
  0x0,
  aX01, // ivar layout
  aPrinter, // name
  __objc_class_Printer_methods, // base methods
  0x0, // base protocols
  __objc_class_Printer_ivars, // ivars
  0x0, // weak ivar layout
  __objc_class_Printer_properties // base properties
}

This looks promising! Here, we seem to have references to methods, the class name, variables, and properties. We have other missing elements too, like the class name. This seems to contain the missing data from the original defined structure, too. We'll take a look at why these seem to differ in the future, right now we're looking at method definitions. Let's take a look at the __objc_class_Printer_methods structure:

__objc_class_Printer_methods:
00000001000010d8 struct __objc_method_list {
  0x18, // flags
  5 // method count
}
00000001000010e0 struct __objc_method {
  aPrintmsg, // name
  aV1608, // signature
  -[Printer printMsg] // implementation
}

00000001000010f8 struct __objc_method {
  aPrintstring, // name
  aV240816, // signature
  -[Printer printString:] // implementation
}

0000000100001110 struct __objc_method {
  aCxxdestruct, // name
  aV1608, // signature
  -[Printer .cxx_destruct] // implementation
}

0000000100001128 struct __objc_method {
  aStrtoprint_100000f18, // name
  a1608, // signature
  -[Printer str_to_print] // implementation
}

0000000100001140 struct __objc_method {
  aSetstrtoprint, // name
  aV240816, // signature
  -[Printer setStr_to_print:] // implementation
}

This is what we're looking for — let's take a closer look. This is a list of methods, defined by the __objc_method_list structure. We have a list of five methods here, some of which we defined (e.g. printString) and some we didn't (e.g. cxx_destruct). Each of these entries have pointers to the implementation functions too (I'm using Hopper here, which is very friendly to Objective-C disassembly and function demangling, which is why this section of the disassembly is so easy to read).

Each of the method structures define the method name, signature, and a pointer to an implementation function. Let's take a look at the decompiled printString method implementation:

-(void)printString:(void *)arg2 {
  var_18 = 0x0;
  objc_storeStrong(&var_18, arg2);
  [self setStr_to_print:var_18];
  [self printMsg];
  objc_storeStrong(&var_18, 0x0);
  return;
}

And here's our original:

- (void) printString: (NSString*) message {
  self.str_to_print = message;
  [self printMsg];
}

Pretty close! We have a few extra things in the decompiled method related to reference counting, but the code is pretty much what we'd expect.

So now we see how classes are defined, or at least some of the major elements (we haven't discussed Protocols or Properties, for example, but you can see how properties are supported in the disassembly here, specifically via the setStr_to_print method).

There's lots of interesting stuff to continue to unravel here — how these methods are actually called, for example, or how Protocols are supported, or why we see the data stored in the executable that seems a bit off from header file definitions. We'll continue to explore some of this later, but it's time we took a look at how this kind of thing is implemented in Swift.

Topics:
internals ,objective-c ,web dev

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}