通过runtime访问成员变量、属性、方法、协议列表

·  阅读 53

以下的例子我们都用ITextFiled来探究,开始之前我们需要导入头文件 #import <objc/runtime.h>

1.访问成员变量列表

- (NSArray *)getIvarListOfClass:(Class)cls {

    unsigned int ivarCount;

    NSMutableArray *array = @[].mutableCopy;

    Ivar *ivarList = class_copyIvarList([cls class], &ivarCount);

    

    for(int i = 0;i < ivarCount; i++) {

        [array addObject:[NSString stringWithUTF8String:ivar_getName(ivarList[i])]];

        //打印成员变量名称-类型

//        NSLog(@"name = %s,type = %s",ivar_getName(ivarList[i]),ivar_getTypeEncoding(ivarList[i]));

    }

    free(ivarList);

    

    return array.copy;

}
复制代码

打印截图:

image.png

2.访问属性列表

- (NSArray *)getPropertyListOfClass:(Class)cls {

    NSMutableArray *array = @[].mutableCopy;

    unsigned int propertyCount;

    objc_property_t * propertylist = class_copyPropertyList([cls class], &propertyCount);

    for(int i = 0;i < propertyCount; i++) {

        [array addObject:[NSString stringWithUTF8String:property_getName(propertylist[i])]];

    }

    free(propertylist);

    return array.copy;

}
复制代码

打印截图:

image.png

3.访问方法列表

- (NSArray *)getMethodListOfClass:(Class)class {

    unsigned int count;

    Method *methodList = class_copyMethodList(class, &count);

    NSMutableArray *methodArray = @[].mutableCopy;

    for (int i = 0; i < count; i++) {

        Method method = methodList[i];

        [methodArray addObject:NSStringFromSelector(method_getName(method))];

    }

    /// 使用copy create创建的c,都需要释放内存

    free(methodList);

    return methodArray.copy;

}
复制代码

打印截图:

image.png

4.访问协议列表

- (NSArray *)getProtocolListOfClass:(Class)cls {

    unsigned int protocolCount;

    NSMutableArray *array = @[].mutableCopy;

    Protocol *__unsafe_unretained  _Nonnull * _Nullable protocolsList = class_copyProtocolList([cls class], &protocolCount);

    for (int i = 0; i < protocolCount; i++) {

        [array addObject:[NSString stringWithUTF8String:protocol_getName(protocolsList[i])]];

    }

    free(protocolsList);

    return array.copy;

}
复制代码

打印截图:

image.png

应用

现在有一个需求,修改UITextFiled的placeholder提示符

1.先看看我们通常的做法吧

        self.textField.attributedPlaceholder = [[NSMutableAttributedString alloc] initWithString:@"请输入用户名" attributes:@{

        NSForegroundColorAttributeName: [UIColor redColor],

        NSFontAttributeName: [UIFont systemFontOfSize:16],

    }];
复制代码

效果图:

image.png

2.通过KVC访问UITextFiled的私有成员变量_placeholderLabel

    self.textField.placeholder = @"请输入用户名";

    [self.textField setValue:[UIColor orangeColor] forKeyPath:@"_placeholderLabel.textColor"];
复制代码

经典错误:'Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug' 在ios 13之前是可以的,但是在ios 13以后,通过这种方式会导致应用奔溃。那么就没有方法访问了吗?那当然有啦,毕竟apple嘛,大家都懂。那么我们来看看怎么实现。

3.通过新的方法

    self.textField.placeholder = @"请输入用户名";
    //获取UITextField类的成员变量
    Ivar placeholder = class_getInstanceVariable([UITextField class], "_placeholderLabel");
    //访问self.textfield的成员变量
    UILabel *placeholderLbl = object_getIvar(self.textField, placeholder);

    placeholderLbl.textColor = [UIColor orangeColor];
复制代码

让我们来看看效果吧。

image.png

看到这里是不是很神奇。这里主要是记录对runtime提供的API的copy进行学习。后面会记录其他方面的学习笔记,如果你有更好的学习内容欢迎在评论区留言,点个赞~

分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改