运行时c函数

// 修改isa,本质就是改变当前对象的类名
    object_setClass(self, [XMGKVONotifying_Person class]);


// self动态添加关联
    // id object:给哪个对象添加关联属性
    // key:属性名
    // value:关联值
    //objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

 

// self获取关联
    //objc_getAssociatedObject(id object, const void *key)
    id observer = objc_getAssociatedObject(self, @"observer");


 默认情况下,如果是以[object message]的方式调用方法,如果object无法响应message消息时,编译器会报错。但如果是以perform…的形式来调用,则需要等到运行时才能确定object是否能接收message消息。如果不能,则程序崩溃。

通常,当我们不能确定一个对象是否能接收某个消息时,会先调用respondsToSelector:来判断一下。如下代码所示:

if ([self respondsToSelector:@selector(method)]) {
    [self performSelector:@selector(method)];
}

摘录其它博客:

@implementation HYBMethodLearn

- (int)testInstanceMethod:(NSString *)name andValue:(NSNumber *)value {
  NSLog(@"%@", name);
  return value.intValue;
}

- (void)getMethods {
  unsigned int outCount = 0;
  Method *methodList = class_copyMethodList(self.class, &outCount);
  
  for (unsigned int i = 0; i < outCount; ++i) {
    Method method = methodList[i];
    
    SEL methodName = method_getName(method);
    NSLog(@"方法名:%@", NSStringFromSelector(methodName));
    
    // 获取方法的参数类型
    unsigned int argumentsCount = method_getNumberOfArguments(method);
    char argName[512] = {};
    for (unsigned int j = 0; j < argumentsCount; ++j) {
      method_getArgumentType(method, j, argName, 512);
      
      NSLog(@"第%u个参数类型为:%s", j, argName);
      memset(argName, '\0', strlen(argName));
    }
    
    char returnType[512] = {};
    method_getReturnType(method, returnType, 512);
    NSLog(@"返回值类型:%s", returnType);
    
    // type encoding
    NSLog(@"TypeEncoding: %s", method_getTypeEncoding(method));
  }
  
  free(methodList);
}


+ (void)test {
  HYBMethodLearn *m = [[HYBMethodLearn alloc] init];
//  [m getMethods];
  
  ((void (*)(id, SEL))objc_msgSend)((id)m, @selector(getMethods));
  
  // 这就是为什么有四个参数的原因
  int returnValue = ((int (*)(id, SEL, NSString *, NSNumber *))
                     objc_msgSend)((id)m,
                                   @selector(testInstanceMethod:andValue:),
                                   @"标哥的技术博客",
                                   @100);
  NSLog(@"return value is %d", returnValue);
  
  // 获取方法
  Method method = class_getInstanceMethod([self class], @selector(testInstanceMethod:andValue:));
  
  // 调用函数
  returnValue = ((int (*)(id, Method, NSString *, NSNumber *))method_invoke)((id)m, method, @"测试使用method_invoke", @11);
  NSLog(@"call return vlaue is %d", returnValue);
}

 


 

给NSMutableArray添加分类

#import "NSMutableArray+Swizzling.h"
#import <objc/runtime.h>
#import <objc/message.h>

@implementation NSMutableArray (Swizzling)
+(void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        //NSMutableArray ---->__NSArrayM
        Method method=class_getInstanceMethod(objc_getClass("__NSArrayM"), @selector(objectAtIndex:));
        
        Method method2=class_getInstanceMethod(objc_getClass("__NSArrayM"), @selector(fdc_objectAtIndex:));
        
        method_exchangeImplementations(method, method2);
    });
}
-(id)fdc_objectAtIndex:(NSInteger)index
{
//    NSLog(@"%s",__func__);  千万别加上这句  不然有bug
    if (self.count == 0) {
        NSLog(@"%s can't get any object from an empty array", __FUNCTION__);
        return nil;
    }
    
    if (index > self.count) {
        NSLog(@"%s index out of bounds in array", __FUNCTION__);
        return nil;
    }
    return [self fdc_objectAtIndex:index];
}
@end

 


 

    Student *obj=[[Student alloc]init];
    
    NSLog(@"instance         :%p", obj);
    NSLog(@"---------------------------------------------");
    NSLog(@"class            :%p", object_getClass(obj));
    NSLog(@"meta class       :%p", object_getClass(object_getClass(obj)));
    NSLog(@"root meta        :%p", object_getClass(object_getClass(object_getClass(obj))));
    NSLog(@"root meta's meta :%p", object_getClass(object_getClass(object_getClass(object_getClass(obj)))));
    NSLog(@"---------------------------------------------");
    NSLog(@"class            :%p", [obj class]);
    NSLog(@"meta class       :%p", [[obj class] class]);
    NSLog(@"root meta        :%p", [[[obj class] class] class]);
    NSLog(@"root meta's meta :%p", [[[[obj class] class] class] class]);
2016-07-14 10:24:05.074 测试[1145:46819] instance         :0x7fed2276d9c0
2016-07-14 10:24:05.075 测试[1145:46819] ---------------------------------------------
2016-07-14 10:24:05.075 测试[1145:46819] class            :0x101417060
2016-07-14 10:24:05.075 测试[1145:46819] meta class       :0x101417038
2016-07-14 10:24:05.076 测试[1145:46819] root meta        :0x101c75198
2016-07-14 10:24:05.076 测试[1145:46819] root meta's meta :0x101c75198
2016-07-14 10:24:05.076 测试[1145:46819] ---------------------------------------------
2016-07-14 10:24:05.076 测试[1145:46819] class            :0x101417060
2016-07-14 10:24:05.076 测试[1145:46819] meta class       :0x101417060
2016-07-14 10:24:05.077 测试[1145:46819] root meta        :0x101417060
2016-07-14 10:24:05.077 测试[1145:46819] root meta's meta :0x101417060

类簇

类簇的概念:一个父类有好多子类,父类在返回自身对象的时候,向外界隐藏各种细节,根据不同的需要返回的其实是不同的子类对象,这其实就是抽象类工厂的实现思路,iOS最典型的就是NSNumber。

NSNumber,NSArray,NSDictionary、NSString、NSTimer…这说明大多数的OC类都是类簇实现的;

    NSNumber *intNum = [NSNumber numberWithInt:1];
    NSNumber *boolNum = [NSNumber numberWithBool:YES];
    NSLog(@"intNum :%@", [intNum class]);
    NSLog(@"boolNum:%@", [boolNum class]);
    NSLog(@"Superclass:%@", class_getSuperclass([boolNum class]));
    NSLog(@"Superclass:%@", class_getSuperclass([intNum class]));
2016-07-14 10:30:21.166 测试[1179:51674] intNum :__NSCFNumber
2016-07-14 10:30:21.167 测试[1179:51674] boolNum:__NSCFBoolean
2016-07-14 10:30:21.167 测试[1179:51674] Superclass:NSNumber
2016-07-14 10:30:21.167 测试[1179:51674] Superclass:NSNumber

 

posted @ 2016-07-13 12:00  潜意识  阅读(254)  评论(0编辑  收藏  举报