Created
July 9, 2011 04:05
-
-
Save TooTallNate/1073294 to your computer and use it in GitHub Desktop.
low-level objc runtime apis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* | |
!*.m | |
!Makefile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To compile: gcc -o array array.m -lobjc -framework Foundation | |
#include <objc/runtime.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
int main() { | |
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY); | |
if (sdl_library == NULL) { | |
printf("Got dlopen error!\n"); | |
} else { | |
printf("dlopen successful!\n"); | |
// Set up an NSAutoreleasePool | |
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool"); | |
id pool = class_createInstance(nsautoreleasepool, 0); | |
SEL initSel = sel_registerName("init"); | |
id poolAfterInit = objc_msgSend(pool, initSel); | |
// Create an NSMutableArray | |
Class nsmutablearray = objc_getClass("NSMutableArray"); | |
// Regular way to create an NSMutableArray, | |
// equivalent to [[NSMutableArray alloc] initWithCapacity: 10] | |
id array = objc_msgSend(nsmutablearray, sel_registerName("alloc")); | |
id arrayAfterInit = objc_msgSend(array, sel_registerName("initWithCapacity:"), 10); | |
// Alternative, shorthand way of creating an NSMutableArray, | |
// equivalent to [NSMutableArray arrayWithCapacity: 10] | |
//id arrayAfterInit = objc_msgSend(nsmutablearray, sel_registerName("arrayWithCapacity:"), 10); | |
// Add an NSString and the nsma class reference to the array | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"test"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), nsmutablearray); | |
// Print out the length and debug printout | |
NSLog(@"%d", objc_msgSend(arrayAfterInit, sel_registerName("count"))); | |
NSLog(@"%@", arrayAfterInit); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#include <objc/runtime.h> | |
#include <Block.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
int main() { | |
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY); | |
if (sdl_library == NULL) { | |
printf("Got dlopen error!\n"); | |
} else { | |
printf("dlopen successful!\n"); | |
// Set up an NSAutoreleasePool | |
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool"); | |
id pool = class_createInstance(nsautoreleasepool, 0); | |
SEL initSel = sel_registerName("init"); | |
id poolAfterInit = objc_msgSend(pool, initSel); | |
// Create an NSMutableArray | |
Class nsmutablearray = objc_getClass("NSMutableArray"); | |
// Regular way to create an NSMutableArray, | |
// equivalent to [[NSMutableArray alloc] initWithCapacity: 10] | |
id array = objc_msgSend(nsmutablearray, sel_registerName("alloc")); | |
id arrayAfterInit = objc_msgSend(array, sel_registerName("initWithCapacity:"), 10); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"a"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"b"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"c"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"d"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"e"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"f"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"g"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"h"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"i"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"j"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"k"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"l"); | |
id b = ^(id x, NSUInteger index, BOOL *stop){ | |
NSLog(@"%@", x); | |
}; | |
NSLog(@"%@", b); | |
objc_msgSend(arrayAfterInit, sel_registerName("enumerateObjectsUsingBlock:"), b); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#include <objc/runtime.h> | |
#include <Block.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
struct __block_literal_1 { | |
void *isa; | |
int flags; | |
int reserved; | |
void (*invoke)(struct __block_literal_1 *, id obj, NSUInteger idx, BOOL *stop); | |
struct __block_descriptor_1 *descriptor; | |
}; | |
// This is the regular C function we are turning into a Block. | |
void __block_invoke_1(struct __block_literal_1 *_block, id obj, NSUInteger idx, BOOL *stop) { | |
NSLog(@"%d: %@", idx, obj); | |
} | |
static struct __block_descriptor_1 { | |
unsigned long int reserved; | |
unsigned long int Block_size; | |
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1) }; | |
int main() { | |
printf("sizeof(int): %lu\n", sizeof(int)); | |
printf("sizeof(void *): %lu\n", sizeof(void *)); | |
printf("sizeof(void (*)()): %lu\n", sizeof(void (*)())); | |
printf("sizeof(struct __block_descriptor *): %lu\n", sizeof(struct __block_descriptor *)); | |
printf("sizeof(__block_literal_1): %lu\n", sizeof(struct __block_literal_1)); | |
printf("sizeof(__block_descriptor_1): %lu\n", sizeof(struct __block_descriptor_1)); | |
printf(" calculated: %lu\n", sizeof(void*)+sizeof(int)+sizeof(int)+sizeof(void (*)())+sizeof(struct __block_descriptor_1 *)); | |
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY); | |
if (sdl_library == NULL) { | |
printf("Got dlopen error!\n"); | |
} else { | |
printf("dlopen successful!\n"); | |
// Set up an NSAutoreleasePool | |
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool"); | |
id pool = class_createInstance(nsautoreleasepool, 0); | |
SEL initSel = sel_registerName("init"); | |
id poolAfterInit = objc_msgSend(pool, initSel); | |
// Create an NSMutableArray | |
Class nsmutablearray = objc_getClass("NSMutableArray"); | |
// Regular way to create an NSMutableArray, | |
// equivalent to [[NSMutableArray alloc] initWithCapacity: 10] | |
id array = objc_msgSend(nsmutablearray, sel_registerName("alloc")); | |
id arrayAfterInit = objc_msgSend(array, sel_registerName("initWithCapacity:"), 10); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"a"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"b"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"c"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"d"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"e"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"f"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"g"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"h"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"i"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"j"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"k"); | |
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"l"); | |
struct __block_literal_1 _block_literal = { | |
&_NSConcreteStackBlock, | |
//&_NSConcreteGlobalBlock, | |
(1<<29), | |
0, | |
__block_invoke_1, | |
&__block_descriptor_1 | |
}; | |
id b = (id)&_block_literal; | |
NSLog(@"%@", b); | |
objc_msgSend(arrayAfterInit, sel_registerName("enumerateObjectsUsingBlock:"), b); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <objc/runtime.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
int main(int argc, char **argv) { | |
dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", RTLD_LAZY); | |
dlopen("/System/Library/Frameworks/AppKit.framework/AppKit", RTLD_LAZY); | |
dlopen("/System/Library/Frameworks/Cocoa.framework/Cocoa", RTLD_LAZY); | |
char * className = argc == 2 ? argv[1] : "NSMutableArray"; | |
Class NSMA = objc_getClass(className); | |
if (!NSMA) { | |
printf("Could not load Class: %s\n", className); | |
return 1; | |
} | |
const char *name = class_getName(NSMA); | |
printf("class_getName: %s\n", name); | |
int version = class_getVersion(NSMA); | |
printf("class_getVersion: %d\n", version); | |
const char *weakIvarLayout = class_getWeakIvarLayout(NSMA); | |
printf("class_getWeakIvarLayout: %s\n", weakIvarLayout); | |
BOOL isMetaClass = class_isMetaClass(NSMA); | |
printf("class_isMetaClass: %s\n", isMetaClass ? "yes" : "no"); | |
// get the metaclass | |
id metaclass = NSMA->isa; | |
isMetaClass = class_isMetaClass(metaclass); | |
printf("class_isMetaClass(isa): %s\n", isMetaClass ? "yes" : "no"); | |
// Look up the Ivars | |
unsigned int i = 0; | |
unsigned int numIvars = 999999; | |
Ivar *ivars = NULL; | |
ivars = class_copyIvarList(NSMA, &numIvars); | |
printf("\nNum ivars: %d\n", numIvars); | |
for (; i<numIvars; i++) { | |
Ivar ivar = ivars[i]; | |
const char *ivarName = ivar_getName(ivar); | |
printf(" %s (%s)\n", ivarName, ivar_getTypeEncoding(ivar)); | |
} | |
free(ivars); | |
// Copy the Property List | |
unsigned int numProps = 999999; | |
objc_property_t *props = NULL; | |
props = class_copyPropertyList(NSMA, &numProps); | |
printf("\nNum props: %d\n", numProps); | |
for (i=0; i<numProps; i++) { | |
} | |
free(props); | |
// Copy Protocol List | |
unsigned int numProtocols = 9999999; | |
Protocol **ps = class_copyProtocolList(NSMA, &numProtocols); | |
printf("\nNum Protocols: %d\n", numProtocols); | |
for (i=0; i<numProtocols; i++) { | |
Protocol *p = ps[i]; | |
printf(" %s\n", protocol_getName(p)); | |
} | |
free(ps); | |
// Copy Method List (instance methods) | |
unsigned int numMethods = 99999999; | |
Method * methods = NULL; | |
methods = class_copyMethodList(NSMA, &numMethods); | |
printf("\nNum Instance Methods: %d\n", numMethods); | |
for (i=0; i<numMethods; i++) { | |
Method m = methods[i]; | |
SEL name = method_getName(m); | |
printf(" %s (%s)\n", sel_getName(name), method_getTypeEncoding(m)); | |
} | |
free(methods); | |
// Copy Method List (class methods) | |
numMethods = 0; | |
methods = NULL; | |
methods = class_copyMethodList(metaclass, &numMethods); | |
printf("\nNum Class Methods: %d\n", numMethods); | |
for (i=0; i<numMethods; i++) { | |
Method m = methods[i]; | |
SEL name = method_getName(m); | |
printf(" %s (%s)\n", sel_getName(name), method_getTypeEncoding(m)); | |
} | |
free(methods); | |
// get superclass | |
Class superclass = NSMA; | |
printf("\nWalking inheritance chain:\n"); | |
printf(" %s\n", name); | |
unsigned int numClasses = 0; | |
do { | |
printf(" "); | |
numClasses++; | |
superclass = class_getSuperclass(superclass); | |
for (i=0; i<numClasses; i++) { | |
printf(" "); | |
} | |
printf("↳ %s\n", class_getName(superclass)); | |
} while(superclass); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <objc/runtime.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
int main(int argc, char **argv) { | |
dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY); | |
unsigned int i, n; | |
Protocol **ps = NULL; | |
ps = objc_copyProtocolList(&n); | |
printf("Num Protocols: %d\n", n); | |
// Do stuff with `classes` | |
for (i=0; i<n; i++) { | |
Protocol *p = ps[i]; | |
printf("%s\n", protocol_getName(p)); | |
} | |
free(ps); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To compile: gcc -o getClassList getClassList.m -lobjc -framework Foundation | |
#import <Foundation/Foundation.h> | |
#include <objc/runtime.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
int main(int argc, char **argv) { | |
dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", RTLD_LAZY); | |
dlopen("/System/Library/Frameworks/AppKit.framework/AppKit", RTLD_LAZY); | |
int i = 0; | |
int numClasses; | |
Class * classes = NULL; | |
numClasses = objc_getClassList(NULL, 0); | |
printf("Num classes: %d\n", numClasses); | |
if (numClasses > 0 ) { | |
classes = malloc(sizeof(Class) * numClasses); | |
numClasses = objc_getClassList(classes, numClasses); | |
// Do stuff with `classes` | |
for (i=0; i<numClasses; i++) { | |
Class c = classes[i]; | |
printf("%s\n", class_getName(c)); | |
} | |
free(classes); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To compile: gcc -o hello hello.m -lobjc | |
#include <objc/runtime.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
int main() { | |
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY); | |
if (sdl_library == NULL) { | |
printf("Got dlopen error!\n"); | |
} else { | |
printf("dlopen successful!\n"); | |
// Set up an NSAutoreleasePool | |
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool"); | |
id pool = class_createInstance(nsautoreleasepool, 0); | |
SEL initSel = sel_registerName("init"); | |
id poolAfterInit = objc_msgSend(pool, initSel); | |
// Set up a NSString with the contents "Hello World" from a C string | |
Class nsstring = objc_getClass("NSString"); | |
SEL stringUTF8sel = sel_registerName("stringWithUTF8String:"); | |
id hello = objc_msgSend(nsstring, stringUTF8sel, "Hello World\n"); | |
// Print it back out as a C string | |
printf("%s", (char *)objc_msgSend(hello, sel_registerName("UTF8String"))); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CC = gcc | |
SRC_FILES = $(wildcard *.m) | |
OUT_FILES = $(SRC_FILES:.m=) | |
.PHONY: all | |
all: $(OUT_FILES) | |
%: %.m | |
$(CC) -g -lobjc -framework Foundation -o $@ $< | |
.PHONY: clean | |
clean: | |
rm -f $(OUT_FILES) | |
rm -rf $(SRC_FILES:.m=.dSYM) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To compile: gcc -o scriptingbridge scriptingbridge.m -lobjc -framework Foundation | |
#import <Foundation/Foundation.h> | |
#include <objc/runtime.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
int main(int argc, char **argv) { | |
dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY); | |
dlopen("/System/Library/Frameworks/ScriptingBridge.framework/Versions/Current/ScriptingBridge", RTLD_LAZY); | |
// Set up an NSAutoreleasePool | |
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool"); | |
id pool = class_createInstance(nsautoreleasepool, 0); | |
SEL initSel = sel_registerName("init"); | |
id poolAfterInit = objc_msgSend(pool, initSel); | |
// Create an instance of the local iTunes installation | |
Class sbapplication = objc_getClass("SBApplication"); | |
id itunes = objc_msgSend(sbapplication, sel_registerName("applicationWithBundleIdentifier:"), @"com.apple.iTunes"); | |
// Is iTunes running? | |
id running = objc_msgSend(itunes, sel_registerName("isRunning")); | |
NSLog(@"iTunes Running: %d", running); | |
// Print out the name of the iTunes application | |
id name = objc_msgSend(itunes, sel_registerName("name")); | |
NSLog(@"Name: %@", name); | |
// Print out the current volume | |
NSInteger curVol = (NSInteger) objc_msgSend(itunes, sel_registerName("soundVolume")); | |
NSLog(@"Current Volume: %d", curVol); | |
// If an argument was passed, assume it's an integer and set iTunes' volume | |
if (argc > 1) { | |
NSInteger volToSet = atoi(argv[1]); | |
objc_msgSend(itunes, sel_registerName("setSoundVolume:"), volToSet); | |
NSLog(@"Set Volume to: %d", volToSet); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To compile: gcc -o array array.m -lobjc -framework Foundation | |
#import <Foundation/Foundation.h> | |
#include <objc/runtime.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
int main() { | |
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY); | |
if (sdl_library == NULL) { | |
printf("Got dlopen error!\n"); | |
} else { | |
printf("dlopen successful!\n"); | |
} | |
printf("sizeof(Class): %lu\n", sizeof(Class)); | |
printf("sizeof(Method): %lu\n", sizeof(Method)); | |
printf("sizeof(unsigned long int): %lu\n", sizeof(unsigned long int)); | |
printf("sizeof(struct int, void*): %lu\n", sizeof(struct test { int test; void * ptr; })); | |
printf("sizeof(struct int, int, void*): %lu\n", sizeof(struct test2 { int test; int test2; void * ptr; })); | |
printf("sizeof(struct void*, int, int, void*): %lu\n", sizeof(struct test3 { void *ptr2; int test2; void * ptr; })); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <objc/runtime.h> | |
#include <objc/objc-exception.h> | |
#include <dlfcn.h> | |
#include <stdio.h> | |
void uncaughtExceptionHandler (id exception) { | |
fprintf(stderr, "Inside uncaughtException handler!!!!\n"); | |
fprintf(stderr, "Exception Type: %s\n", (const char *)objc_msgSend(objc_msgSend(exception, sel_registerName("name")), sel_registerName("UTF8String"))); | |
fprintf(stderr, "Exception Reason: %s\n", (const char *)objc_msgSend(objc_msgSend(exception, sel_registerName("reason")), sel_registerName("UTF8String"))); | |
} | |
int main() { | |
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY); | |
if (sdl_library == NULL) { | |
printf("Got dlopen error!\n"); | |
} else { | |
printf("dlopen successful!\n"); | |
// Set up an NSAutoreleasePool | |
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool"); | |
id pool = class_createInstance(nsautoreleasepool, 0); | |
SEL initSel = sel_registerName("init"); | |
id poolAfterInit = objc_msgSend(pool, initSel); | |
// Set up an uncaughtException handler | |
objc_setUncaughtExceptionHandler((objc_uncaught_exception_handler)uncaughtExceptionHandler); | |
// Intentionally throw an exception, by sending a bad selector to an object | |
Class nsobject = objc_getClass("NSObject"); | |
SEL badSel = sel_registerName("badSelector"); | |
objc_msgSend(nsobject, badSel); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Realise this was created a long time ago but is a really useful resource.
objc_msgSend
appears to have a odd definition where the params are just inserted wherever. Do you know if it's possible to send parameters gradually to an object by repeatedly sendingobjc_msgSend()
(or some other function) for parameters instead?Additionally, do you know how to send a named parameter?