美文网首页
iOS RunTime常用内容总结

iOS RunTime常用内容总结

作者: _菩提本无树_ | 来源:发表于2023-01-16 16:54 被阅读0次
    - (void)runtime {
        /// 获取类名
        const char *className = class_getName([NSObject class]);
        
        /// 获取父类
        Class supperClass = class_getSuperclass([self class]);
        
        /// 判断某个类是否是metaclass
        BOOL isMeta =class_isMetaClass([NSObject class]);
        
        /// 获取生成对象需要的大小
        size_t size = class_getInstanceSize([self class]);
        
        /// 获取实例变量(在类中声明变量的时候会自动生成实例变量,加下划线即可获取)
        Ivar ivar = class_getInstanceVariable([self class], "_allDataArr");
        
        /// 这个方法表示的是类变量,但是公开的api是没有这个的,或许是内部使用的方法,目前用不到
        Ivar ivarClass = class_getClassVariable([self class], "");
        
        /// 该函数只能在动态添加类中使用有效,且只能在objc_allocatelasspair()之后和objc_registerClassPair()之前调用,
        /// 动态生成类
        Class Person = objc_allocateClassPair([NSObject class], "Person", 0);
        BOOL addOvar = class_addIvar([Person class], "_myData", sizeof(NSString *), log2(sizeof(NSString *)), "@");
        BOOL addOvar1 = class_addIvar([Person class], "_myData1", sizeof(NSString *), log2(sizeof(NSString *)), "@");
        objc_registerClassPair(Person);
        /// 给成员变量赋值
        id person = Person.new;
        Ivar personIvar = class_getInstanceVariable([Person class], "_myData");
        object_setIvar(person, personIvar, @"test");
        NSLog(@"ivar值:%@",object_getIvar(person, personIvar));
        
        /// 获取实例变量列表
        unsigned int ivarCount;
        Ivar *ivars = class_copyIvarList([self class], &ivarCount);
        
        /// 获取类中使用strong修饰的实例对象列表
        /// 这个方法获取的内容值的解读,参考 https://www.51cto.com/article/493255.html
        const uint8_t *strongs = class_getIvarLayout([self class]);
        int i = 0;
        uint8_t value_s = strongs[i];
        while (value_s != 0x0) {
            printf("\\x%02x\n", value_s);
            value_s = strongs[++i];
        }
        
        /// 获取类中使用weak修饰的实例对象列表(strong和weak都未获得的是基本数据类型)
        const uint8_t *weaks = class_getWeakIvarLayout([DDCollectionCycleController class]);
        
        /// 添加实例对象修饰符(strong,weak,retain......)该方法未理清
        //    class_setIvarLayout([Person class], <#const uint8_t * _Nullable layout#>)
    
        /// 获取属性
        objc_property_t property_t = class_getProperty([self class], "property");
        
        /// 获取属性列表
        unsigned int property_count;
        objc_property_t *property_list = class_copyPropertyList([self class], &property_count);
        
        /// 动态添加方法
        SEL sel = NSSelectorFromString(@"testMethod");
        Method method_t = class_getInstanceMethod([self class], sel);
        BOOL isMethod = class_addMethod([self class], sel, method_getImplementation(method_t), method_getTypeEncoding(method_t));
        
        /// 获取指定对象方法
        Method methodInstance = class_getInstanceMethod([self class], @selector(testMethod));
        
        ///获取类方法
        Method methodClass = class_getClassMethod([self class], @selector(classMethod));
        
        /// 获取方法列表
        unsigned int methodCount;
        Method methodInstance_list = class_copyMethodList([self class], &methodCount);
        
        /// 方法替换
        class_replaceMethod([self class], @selector(swizzMethod), class_getMethodImplementation([self class], @selector(originMethod)), method_getTypeEncoding(class_getInstanceMethod([self class], @selector(originMethod))));
        
        /// 获取方法的imp
        IMP imp = class_getMethodImplementation([self class], @selector(originMethod));
        
        /// 查找类中是否包含某个实例方法,但是官方不建议使用这个方法建议使用 respondsToSelector: 或者 instancesRespondToSelector:
        BOOL isContainMethod = class_respondsToSelector([self class], @selector(originMethod));
        
        /// 添加协议Protocol到类中
        Protocol *protocol = @protocol(UITextFieldDelegate);
        BOOL isProtocol = class_addProtocol([self class], protocol);
        
        /// 添加属性
        Class currentClass = [self class];
        NSString * propertyName = @"myProperty";
        // type(举例NSString类型)
        objc_property_attribute_t type = { "T", "@\"NSString\""};
        // C = copy
        objc_property_attribute_t ownership0 = { "C", "" };
        // N = nonatomic
        objc_property_attribute_t ownership = { "N", "" };
        // instance variable name
        objc_property_attribute_t backingivar  = { "V", [[NSString stringWithFormat:@"_%@", propertyName] UTF8String] };
        // 对比系统生成的顺序,例如我们静态添加的grade属性
        objc_property_attribute_t attrs[] = { type, ownership0, ownership, backingivar};
        BOOL isProperty = class_addProperty(self.class, "myProperty", attrs, 4);
        if (!isProperty) {
            // 添加属性失败,替换属性
            class_replaceProperty(currentClass, "myProperty", attrs, 4);
        }
        // 添加get和set方法不好使,一直闪退,所以通过关联对象的方式添加
        // BOOL add = class_addMethod(currentClass, NSSelectorFromString(propertyName), (IMP)getter, "@@:");
        // BOOL addM = class_addMethod(currentClass, NSSelectorFromString(@"setMyProperty:"), (IMP)setter, "v@:@");
        objc_setAssociatedObject(self, "myProperty", @"12233", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        NSString *valueData = objc_getAssociatedObject(self, "myProperty");
        
        /// 检测某个类是否遵循某个协议,官方不建议使用这个方法,使用NSObject的conformsToProtocol:
        BOOL isConformsProtocol = class_conformsToProtocol([self class], @protocol(UITableViewDelegate));
        
        /// 设置类的版本号,不明白这个用来干啥的
        class_setVersion(self.class, 2);
        /// 获取类的版本号
        int n = class_getVersion(self.class);
        
        ///objc_getFutureClass , objc_setFutureClass这两个方法官方原话是Do not call this function yourself
        
        /// 动态添加类
        Class PlusClass = objc_allocateClassPair([NSObject class], "PlusClass", 0);
        objc_registerClassPair(PlusClass);
        /// 创建对象
        id plus = class_createInstance(PlusClass.class, sizeof(unsigned));
        id strInstance = class_createInstance(NSString.class, sizeof(unsigned));
        strInstance = @"string";
        /// 释放类     !!!不要调用这个方法,如果有子类继承或者对象使用这个类
        /// objc_disposeClassPair(PlusClass);
        /// objc_destructInstance,objc_constructInstance arc下无法使用
        
        /// 获取实例关联的信息,一个list
        void * indexedIvars = object_getIndexedIvars(plus);
        
        /// 给实例变量赋值
        object_setIvar(person, personIvar, @"上面已经赋值了,我是第二次赋值");
        
        /// 获取实例变量Ivar存储的值,前提是保证Ivar存在
        id ivar_item = object_getIvar(person, personIvar);
        
        /// 根据对象获取类名
        char *name = object_getClassName(person);
        
        /// 获取类对象
        Class class = object_getClass(person);
        
        /// 讲一个对象设置其他类类型,返回之前的class
        Class replaceClass = object_setClass(plus, NSString.class);
        plus = @"11111";
        
        /// 获取已注册的类的列表,以下代码为官方提供使用案例
        int numClasses;
        Class * classes = NULL;
        classes = NULL;
        numClasses = objc_getClassList(NULL, 0);
        if(numClasses > 0){
            /// 开内存
            classes = (Class *)realloc(classes, sizeof(Class) * numClasses);
            numClasses = objc_getClassList(classes, numClasses);
            for (int i = 0; i < numClasses; i++) {
                const char *className = class_getName(classes[i]);
    //            NSLog(@"%s", className);
            }
    
        }
        free(classes);
    
        /// 获取已注册的类比上面的省事
        unsigned int outCount;
        Class *copyClasses = objc_copyClassList(&outCount);
        for (int i = 0; i < outCount; i++) {
            const char *className = class_getName(classes[i]);
    //            NSLog(@"%s", className);
        }
    
        /// 通过类名获取类,   objc_getClass,objc_lookUpClass,objc_getRequiredClass,作用一样,但是注意📢objc_getRequiredClass这个更危险,找不到会杀死当前进程
        Class lookUpClass = objc_lookUpClass("DDCollectionCycleController");
        Class tmp = objc_getRequiredClass("DDCollectionCycleController");
        
        /// 获取元类对象,通过终端发现元类是NSObject
        id meta = objc_getMetaClass("UIViewController");
        /// po meta
        /// UIViewController
    
        /// e object_getClass(meta)
        /// (Class _Nullable) $1 = 0x0000000229060db0
        /// (lldb) po $1
        /// NSObject
    
        /// 获取实例对象的name
        char * ivar_name = ivar_getName(personIvar);
        
        /// 获取实例对象的编码方式
        char *ivar_type = ivar_getTypeEncoding(personIvar);
        
        /// 创建关联对象
        objc_setAssociatedObject(person, @"user_name", @"DDS", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        /// 获取关联对象的值
        id user_name = objc_getAssociatedObject(person, @"user_name");
        /// 删除obj全部关联对象
        /// objc_removeAssociatedObjects(person);
        
        /// 消息发送objc_msgSend,这种写法需要引入<objc/message.h>,他还有好几个兄弟,不一一介绍
        ((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)self, sel_registerName("test1:"),@"");
        
        
        /// 方法调用
        /// method_invoke
        /// 择日继续更新
        
        
        
        
        NSLog(@"%s",className);
        
    }
    
    + (void)classMethod {
        
    }
    - (void)originMethod {
        
    }
    - (void)swizzMethod {
        
    }
    - (void)test1:(NSString *)t {
        
    }
    
    id getter(id self, SEL _cmd) {
        NSString *key = [NSString stringWithFormat:@"_%@",NSStringFromSelector(_cmd)];
        Ivar ivar = class_getInstanceVariable([self class], key.UTF8String);
        id value = object_getIvar(self, ivar);
        return value;
    }
    
    void setter(id self, SEL _cmd, id newValue) {
        //移除set
        NSString *key = [NSStringFromSelector(_cmd) stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""];
        //首字母小写(不支持开发者故意把属性名称首字母大写的可能)
        NSString *head = [key substringWithRange:NSMakeRange(0, 1)];
        head = [head lowercaseString];
        key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:head];
        //移除后缀 ":"
        key = [key stringByReplacingCharactersInRange:NSMakeRange(key.length - 1, 1) withString:@""];
        Ivar ivar = class_getInstanceVariable([self class], [NSString stringWithFormat:@"_%@",key].UTF8String);
        object_setIvar(self, ivar, newValue);
    }
    
    

    相关文章

      网友评论

          本文标题:iOS RunTime常用内容总结

          本文链接:https://www.haomeiwen.com/subject/rcyacdtx.html