Objective-C
Objective-C Objective-C Objc Runtime Objc Runtime Runtime C C
Runtime
- C C runtime
- [object doSomething] (object) (doSomething) runtime
Objective-C runtime Modern runtime Legacy runtime Modern Runtime 64 Mac OS X Apps iOS Apps Legacy Runtime 32 Mac OS X Apps
runtime Runtime
Class
Objective-C Class objc_class typedef struct objc_class *Class;
objc/runtime.h objc_class struct objc_class {
Search
|
Navigate... Navigate... |
Navigate... |
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class
const char *name
long version
long info
long instance_size
struct objc_ivar_list *ivars
struct objc_method_list **methodLists
struct objc_cache *cache
struct objc_protocol_list *protocols
#endif
} OBJC2_UNAVAILABLE;
OBJC2_UNAVAILABLE; //
OBJC2_UNAVAILABLE; //
OBJC2_UNAVAILABLE; // 0 OBJC2_UNAVAILABLE; // OBJC2_UNAVAILABLE; // OBJC2_UNAVAILABLE; // OBJC2_UNAVAILABLE; // OBJC2_UNAVAILABLE; //
OBJC2_UNAVAILABLE; //
- isa Objective-C Class isa metaClass( )
- super_class ( NSObject NSProxy) super_class NULL
- cache isa
methodLists cache cache runtime cache cache methodLists
4. version cache
NSArray *array = [[NSArray alloc] init];
- [NSArray alloc] NSArray +alloc NSObject
- NSObject +alloc NSArray isa NSArray
+alloc cache
- -init NSArray cache
- [[NSArray alloc] init] cache
objc_object id objc_object (objc/objc.h)
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
isa Objective-C isa Runtime selector
objc_object NSObject alloc allocWithZone: class_createInstance objc_object
id objc_object C++ C void *
objc_cache
objc_class cache objc_cache
struct objc_cache {
unsigned int mask /* total = mask + 1 */
unsigned int occupied
Method buckets[1]
};
OBJC2_UNAVAILABLE;
OBJC2_UNAVAILABLE;
OBJC2_UNAVAILABLE;
- mask bucket Objective-C runtime selector AND (index = (mask & selector)) hash
- occupied bucket
- buckets Method mask+1 NULL bucket
bucket
(Meta Class)
( ) NSArray *array = [NSArray array];
+array NSArray NSArray objc_object isa isa +array isa objc_class meta-class
meta-class runtime meta-class
meta-class meta-class
meta-class isa Objective-C meta-class isa meta-class NSObject meta-class NSObject meta-class meta-class isa
objc_class super_class meta-class
NSObject meta-class meta-class
void TestMetaClass(id self, SEL _cmd) {
NSLog(@"This objcet is %p", self);
NSLog(@"Class is %@, super class is %@", [self class], [self superclass]);
Class currentClass = [self class];
for (int i = 0; i < 4; i++) {
NSLog(@"Following the isa pointer %d times gives %p", i, currentClass);
currentClass = objc_getClass((__bridge void *)currentClass);
}
NSLog(@"NSObject's class is %p", [NSObject class]);
NSLog(@"NSObject's meta class is %p", objc_getClass((__bridge void *)[NSObject class]));
}
#pragma mark -
@implementation Test
- (void)ex_registerClassPair {
Class newClass = objc_allocateClassPair([NSError class], "TestClass", 0);
class_addMethod(newClass, @selector(testMetaClass), (IMP)TestMetaClass, "v@:");
objc_registerClassPair(newClass);
id instance = [[newClass alloc] initWithDomain:@"some domain" code:0 userInfo:nil];
[instance performSelector:@selector(testMetaClass)];
}
@end
NSError TestClass testMetaClass TestMetaClass
2014-10-20 22:57:07.352 mountain[1303:41490] This objcet is 0x7a6e22b0
2014-10-20 22:57:07.353 mountain[1303:41490] Class is TestStringClass, super class is NSError
2014-10-20 22:57:07.353 mountain[1303:41490] Following the isa pointer 0 times gives 0x7a6e21b0
2014-10-20 22:57:07.353 mountain[1303:41490] Following the isa pointer 1 times gives 0x0
2014-10-20 22:57:07.353 mountain[1303:41490] Following the isa pointer 2 times gives 0x0
2014-10-20 22:57:07.353 mountain[1303:41490] Following the isa pointer 3 times gives 0x0
2014-10-20 22:57:07.353 mountain[1303:41490] NSObject's class is 0xe10000
2014-10-20 22:57:07.354 mountain[1303:41490] NSObject's meta class is 0x0
for objc_getClass isa NSObject meta-class 0x0 NSObject meta-class
class meta-class
runtime class objc object_
objc_class runtime
(name)
//
const char * class_getName ( Class cls );
● class_getName cls Nil (super_class) (meta-class)
//
Class class_getSuperclass ( Class cls );
// Class
BOOL class_isMetaClass ( Class cls );
● class_getSuperclass cls Nil cls Nil NSObject superclass ● class_isMetaClass cls YES cls Nil NO
(instance_size)
//
size_t class_getInstanceSize ( Class cls );
(ivars) objc_class ivars ivars Ivar( ) runtime
1.
//
Ivar class_getInstanceVariable ( Class cls, const char *name );
//
Ivar class_getClassVariable ( Class cls, const char *name );
//
BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
//
Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
● class_getInstanceVariable name objc_ivar (Ivar) ● class_getClassVariable Objective-C Objective-C
● Objective-C class_addIvar objc_allocateClassPair objc_registerClassPair 1<<alignment ivar log2(sizeof(pointer_type))
● class_copyIvarList objc_ivar outCount free()
2. //
objc_property_t class_getProperty ( Class cls, const char *name );
//
objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
//
BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
//
void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
ivars
3. MAC OS X runtime strong/weak
const uint8_t * class_getIvarLayout ( Class cls );
void class_setIvarLayout ( Class cls, const uint8_t *layout );
const uint8_t * class_getWeakIvarLayout ( Class cls );
void class_setWeakIvarLayout ( Class cls, const uint8_t *layout );
objc_registerClassPair (methodLists)
//
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
//
Method class_getInstanceMethod ( Class cls, SEL name );
//
Method class_getClassMethod ( Class cls, SEL name );
//
Method * class_copyMethodList ( Class cls, unsigned int *outCount );
//
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
//
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );
// selector
BOOL class_respondsToSelector ( Class cls, SEL sel );
● class_addMethod NO method_setImplementation Objective-C C —self _cmd (IMP )
void myMethodIMP(id self, SEL _cmd)
{
// implementation ....
}
types
● class_getInstanceMethod class_getClassMethod class_copyMethodList
● class_copyMethodList class_copyMethodList(object_getClass(cls), &count)( ) outCount free()
● class_replaceMethod name class_addMethod name method_setImplementation
● class_getMethodImplementation method_getImplementation(class_getInstanceMethod(cls, name)) runtime selector
● class_respondsToSelector NSObject respondsToSelector: instancesRespondToSelector: (objc_protocol_list)
//
BOOL class_addProtocol ( Class cls, Protocol *protocol );
//
BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );
//
Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );
● class_conformsToProtocol NSObject conformsToProtocol: ● class_copyProtocolList free()
(version)
//
int class_getVersion ( Class cls );
//
void class_setVersion ( Class cls, int version );
runtime CoreFoundation tool-free bridging Class objc_getFutureClass ( const char *name );
void objc_setFutureClass ( Class cls, const char *name );
(Example)
//-----------------------------------------------------------
// MyClass.h
@interface MyClass : NSObject <NSCopying, NSCoding>
@property (nonatomic, strong) NSArray *array;
@property (nonatomic, copy) NSString *string;
- (void)method1;
- (void)method2;
+ (void)classMethod1;
@end
//-----------------------------------------------------------
// MyClass.m
#import "MyClass.h"
@interface MyClass () {
NSInteger _instance1;
NSString * _instance2;
}
@property (nonatomic, assign) NSUInteger integer;
- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2;
@end
@implementation MyClass
+ (void)classMethod1 {
}
- (void)method1 {
NSLog(@"call method method1");
}
- (void)method2 {
}
- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2 {
NSLog(@"arg1 : %ld, arg2 : %@", arg1, arg2);
}
@end
//-----------------------------------------------------------
// main.h
#import "MyClass.h"
#import "MySubClass.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyClass *myClass = [[MyClass alloc] init];
unsigned int outCount = 0;
Class cls = myClass.class;
//
NSLog(@"class name: %s", class_getName(cls));
NSLog(@"==========================================================");
//
NSLog(@"super class name: %s", class_getName(class_getSuperclass(cls))); NSLog(@"==========================================================");
//
NSLog(@"MyClass is %@ a meta-class", (class_isMetaClass(cls) ? @"" : @"not")); NSLog(@"==========================================================");
Class meta_class = objc_getMetaClass(class_getName(cls));
NSLog(@"%s's meta-class is %s", class_getName(cls), class_getName(meta_class));
NSLog(@"==========================================================");
//
NSLog(@"instance size: %zu", class_getInstanceSize(cls)); NSLog(@"==========================================================");
//
Ivar *ivars = class_copyIvarList(cls, &outCount); for (int i = 0; i < outCount; i++) {
Ivar ivar = ivars[i];
NSLog(@"instance variable's name: %s at index: %d", ivar_getName(ivar), i);
}
free(ivars);
Ivar string = class_getInstanceVariable(cls, "_string");
if (string != NULL) {
NSLog(@"instace variable %s", ivar_getName(string));
}
NSLog(@"==========================================================");
//
objc_property_t * properties = class_copyPropertyList(cls, &outCount); for (int i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSLog(@"property's name: %s", property_getName(property));
}
free(properties);
objc_property_t array = class_getProperty(cls, "array");
if (array != NULL) {
NSLog(@"property %s", property_getName(array));
}
NSLog(@"==========================================================");
//
Method *methods = class_copyMethodList(cls, &outCount); for (int i = 0; i < outCount; i++) {
Method method = methods[i];
NSLog(@"method's signature: %s", method_getName(method));
}
free(methods);
Method method1 = class_getInstanceMethod(cls, @selector(method1));
if (method1 != NULL) {
NSLog(@"method %s", method_getName(method1));
}
Method classMethod = class_getClassMethod(cls, @selector(classMethod1));
if (classMethod != NULL) {
NSLog(@"class method : %s", method_getName(classMethod));
}
NSLog(@"MyClass is%@ responsd to selector: method3WithArg1:arg2:", class_respondsToSelector(cls, @selector(method3WithArg1:arg2:)) ? @
IMP imp = class_getMethodImplementation(cls, @selector(method1));
imp();
NSLog(@"==========================================================");
//
Protocol * __unsafe_unretained * protocols = class_copyProtocolList(cls, &outCount); Protocol * protocol;
for (int i = 0; i < outCount; i++) {
protocol = protocols[i];
NSLog(@"protocol name: %s", protocol_getName(protocol));
}
NSLog(@"MyClass is%@ responsed to protocol %s", class_conformsToProtocol(cls, protocol) ? @"" : @" not", protocol_getName(protocol));
NSLog(@"==========================================================");
}
return 0; }
2014-10-22 19:41:37.452 RuntimeTest[3189:156810] class name: MyClass
2014-10-22 19:41:37.453 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] super class name: NSObject
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] MyClass is not a meta-class
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] MyClass's meta-class is MyClass
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance size: 48
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _instance1 at index: 0
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _instance2 at index: 1
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _array at index: 2
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _string at index: 3
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] instance variable's name: _integer at index: 4
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] instace variable _string
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] property's name: array
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] property's name: string
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] property's name: integer
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] property array
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] method's signature: method1
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] method's signature: method2
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] method's signature: method3WithArg1:arg2:
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: integer
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: setInteger:
"
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: array
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: string
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: setString:
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: setArray:
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] method's signature: .cxx_destruct
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] method method1
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] class method : classMethod1
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] MyClass is responsd to selector: method3WithArg1:arg2:
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] call method method1
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] protocol name: NSCopying
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] protocol name: NSCoding
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] MyClass is responsed to protocol NSCoding
2014-10-22 19:41:37.468 RuntimeTest[3189:156810] ==========================================================
runtime
//
Class objc_allocateClassPair ( Class superclass, const char *name, size_t extraBytes );
//
void objc_disposeClassPair ( Class cls );
// objc_allocateClassPair void objc_registerClassPair ( Class cls );
● objc_allocateClassPair superclass Nil extraBytes 0 ivars
objc_allocateClassPair class_addMethod class_addIvar objc_registerClassPair
● objc_disposeClassPair
Class cls = objc_allocateClassPair(MyClass.class, "MySubClass", 0);
class_addMethod(cls, @selector(submethod1), (IMP)imp_submethod1, "v@:");
class_replaceMethod(cls, @selector(method1), (IMP)imp_submethod1, "v@:");
class_addIvar(cls, "_ivar1", sizeof(NSString *), log(sizeof(NSString *)), "i");
objc_property_attribute_t type = {"T", "@\"NSString\""};
objc_property_attribute_t ownership = { "C", "" };
objc_property_attribute_t backingivar = { "V", "_ivar1"};
objc_property_attribute_t attrs[] = {type, ownership, backingivar};
class_addProperty(cls, "property2", attrs, 3);
objc_registerClassPair(cls);
id instance = [[cls alloc] init];
[instance performSelector:@selector(submethod1)];
[instance performSelector:@selector(method1)];
2014-10-23 11:35:31.006 RuntimeTest[3800:66152] run sub method 1
2014-10-23 11:35:31.006 RuntimeTest[3800:66152] run sub method 1
//
id class_createInstance ( Class cls, size_t extraBytes );
//
id objc_constructInstance ( Class cls, void *bytes );
//
void * objc_destructInstance ( id obj );
● class_createInstance extraBytes ARC
class_createInstance +alloc class_createInstance NSString
id theObject = class_createInstance(NSString.class, sizeof(unsigned));
id str1 = [theObject init];
NSLog(@"%@", [str1 class]);
id str2 = [[NSString alloc] initWithString:@"test"];
NSLog(@"%@", [str2 class]);
2014-10-23 12:46:50.781 RuntimeTest[4039:89088] NSString
2014-10-23 12:46:50.781 RuntimeTest[4039:89088] __NSCFConstantString
class_createInstance NSString __NSCFConstantString ● objc_constructInstance (bytes) ● objc_destructInstance
1. //
id object_copy ( id obj, size_t size );
//
id object_dispose ( id obj );
A B B A B A A B B B A
NSObject *a = [[NSObject alloc] init];
id newB = object_copy(a, class_getInstanceSize(MyClass.class));
object_setClass(newB, MyClass.class);
object_dispose(a);
2. //
Ivar object_setInstanceVariable ( id obj, const char *name, void *value );
//
Ivar object_getInstanceVariable ( id obj, const char *name, void **outValue );
// void * object_getIndexedIvars ( id obj );
//
id object_getIvar ( id obj, Ivar ivar );
//
void object_setIvar ( id obj, Ivar ivar, id value );
Ivar object_getIvar object_getInstanceVariable object_setIvar object_setInstanceVariable 3.
//
const char * object_getClassName ( id obj );
//
Class object_getClass ( id obj );