iOS高级开发runtime那点事实战 (2)

获取class的property属性List

-(void)printPropertyList{
    unsigned int count ;//存储属性的数量的
    objc_property_t * methodsVar = class_copyPropertyList([UINavigationController class], &count) ;
    for (int i = 0; i < count; i ++) {
        objc_property_t var = methodsVar[i] ;
        NSString * strName =[NSString stringWithUTF8String:property_getName(var)];
        NSString * str =[NSString stringWithUTF8String:property_getAttributes(var)];
        NSLog(@"属性 %@   名字  %@",str,strName);
    }
    free(methodsVar);
}

获取class的的名字

-(void)printfClassName{
    Class clas = NSClassFromString(@"NSString");
   printf("%s", class_getName(clas)); //当clas为空的话 return value 是nil
}

输出:NSString

获取类的父类并输出

-(void)printfClassName:(Class )clas{
   printf("%s", class_getName(clas));
}
-(Class)getSuperClass:(Class)clas{
    return class_getSuperclass(clas);
}

[self printfClassName:[self getSuperClass:NSClassFromString(@"UIView")]];
输出:UIResponder

设置类的父类

/** 
 * Sets the superclass of a given class.
 * 
 * @param cls The class whose superclass you want to set.
 * @param newSuper The new superclass for cls.
 * 
 * @return The old superclass for cls.
 * 
 * @warning You should not use this function. 警告不要用
 */
OBJC_EXPORT Class class_setSuperclass(Class cls, Class newSuper) 
     __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5,__MAC_10_5, __IPHONE_2_0,__IPHONE_2_0);
     
    [self printfClassName:[self getSuperClass:NSClassFromString(@"FY")]];第一次输出NSObjec
    [self setClass:NSClassFromString(@"FY") newSuperClass:NSClassFromString(@"UIImageView")];//设置新的父类
    [self printfClassName:[self getSuperClass:NSClassFromString(@"FY")]];//再次输出是UIImageView 说明设置新的父类是可用的
    

-(void)printfClassName:(Class )clas{
   printf("%s\n", class_getName(clas));
}
-(Class)getSuperClass:(Class)clas{
    return class_getSuperclass(clas);
}
-(Class)setClass:(Class)clas newSuperClass:(Class)superClas{
   return   class_setSuperclass(clas, superClas);
}

对象和类的区分

-(void)isMetaClass{
    NSMutableArray *arr = [[NSMutableArray alloc] init];
    
    [arr addObject:[NSObject class]];
    [arr addObject:[NSValue class]];
    [arr addObject:[NSNumber class]];
    [arr addObject:[NSPredicate class]];
    [arr addObject:@"not a class object"];
    
    for (int i; i<[arr count]; i++) {
        id obj = [arr objectAtIndex:i];
        
        if(class_isMetaClass(object_getClass(obj)))
        {
            //do sth
            NSLog(@"Class: %@", obj);
        }
        else
        {
            NSLog(@"Instance: %@", obj);
        }
    }
}
输出:2016-03-18 15:46:56.235 runTimeObj[18396:2997316] Class: NSObject
2016-03-18 15:46:56.236 runTimeObj[18396:2997316] Class: NSValue
2016-03-18 15:46:56.236 runTimeObj[18396:2997316] Class: NSNumber
2016-03-18 15:46:56.236 runTimeObj[18396:2997316] Class: NSPredicate
2016-03-18 15:46:56.236 runTimeObj[18396:2997316] Instance: not a class object

获得类所占字节的大小

size_t size = class_getInstanceSize(NSClassFromString(@"UIView"));
    printf("%zu",size);

获得类的属性及其属性的类型

-(void)ivarList{
    unsigned int count;
    Ivar * vars = class_copyIvarList(NSClassFromString(@"UIViewController"), &count)//ivar 是结构体 包含 name,offset,type三个可读属性的结构体。
    ;
    for (int i = 0; i < count; i ++) {
        Ivar  var = vars[i];
        [self printIvar:var];
    }
    free(vars);
}
-(void)printIvar:(Ivar)var{//输出结构体
    const  char * name = ivar_getName(var);
    long  offset = ivar_getOffset(var);
    const  char * type = ivar_getTypeEncoding(var);
    printf("%s %ld %s\n",name,offset,type);
}
输出:
_storyboard 152 @"UIStoryboard"
_externalObjectsTableForViewLoading 160 @"NSDictionary"
_topLevelObjectsToKeepAliveFromStoryboard 168 @"NSArray"
_savedHeaderSuperview 176 @"UIView"
_savedFooterSuperview 184 @"UIView"

这些是apple Objectice-C Runtime Reference,具体的更多的在这个网址可见。

上一篇说了一个方法 名字是void method_exchangeImplementations(Method m1, Method m2)
因为这个交换方法只能执行一次,所以解决了交换两次,就相当于没有交换了。具体代码:

static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        void (^__method_swizzling)(Class, SEL, SEL) = ^(Class cls, SEL sel, SEL _sel) {
            Method  method = class_getInstanceMethod(cls, sel);
            Method _method = class_getInstanceMethod(cls, _sel);
            method_exchangeImplementations(method, _method);
        };
      }

在这里是把这个方法封装了一个c函数,保证了只会执行一次,最好把这个dispatch放在+ load函数里面,保证加载次数的减少。
更多博客在www.fgyong.cn可见。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,776评论 0 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,973评论 19 139
  • 本文转载自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex阅读 798评论 0 1
  • 转载:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麦子阅读 770评论 0 2
  • 四点朝前正胯阻力胯和头垂直 压膝盖 压垮5分钟小推车后腿前腿侧腿
    木子雨阅读 173评论 0 0