runtime.h(四)

版本:iOS13.5

runtime.h

需要引入头文件#import
runtime其他方法通道

索引

  • 返回实例变量的名称。
    ivar_getName
  • 返回实例变量的类型字符串。
    ivar_getTypeEncoding
  • 返回实例变量的内存偏移量。
    ivar_getOffset
  • 返回属性的名字。
    property_getName
  • 返回属性的attribute字符串。
    property_getAttributes
  • 返回属性的attribute数组。
    property_copyAttributeList
  • 通过attribute名返回属性的attribute的值。
    property_copyAttributeValue
  • 返回对应名字的协议。
    objc_getProtocol
  • 返回运行时已知的所有协议的数组。
    objc_copyProtocolList
  • 判断协议proto是否符合协议other。
    protocol_conformsToProtocol
  • 判断协议proto和协议other是否相同。
    protocol_isEqual
  • 返回协议的名字。
    protocol_getName
  • 返回协议proto的方法aSel的方法描述结构体。
    protocol_getMethodDescription
  • 返回协议proto的方法描述结构体数组。
    protocol_copyMethodDescriptionList
  • 返回协议proto的对应名字的属性。
    protocol_getProperty
  • 返回协议proto的必需实例属性的数组。
    protocol_copyPropertyList
  • 返回协议proto的属性数组。
    protocol_copyPropertyList2
  • 返回协议proto符合的协议数组。
    protocol_copyProtocolList
  • 创建一个新的协议实例。
    objc_allocateProtocol
  • 注册一个新的协议。
    objc_registerProtocol
  • 向正在构建的协议添加方法。
    protocol_addMethodDescription
  • 向正在构建的协议添加要符合的协议。
    protocol_addProtocol
  • 向正在构建的协议添加属性。
    protocol_addProperty

详解

  • 返回实例变量的名称。
const char * _Nullable ivar_getName(Ivar _Nonnull v)

例子见ivar_getOffset

  • 返回实例变量的类型字符串。
const char * _Nullable ivar_getTypeEncoding(Ivar _Nonnull v) 

例子见ivar_getOffset

  • 返回实例变量的内存偏移量。
ptrdiff_t ivar_getOffset(Ivar _Nonnull v) 

内存偏移量,即该成员变量对于该对象的内存地址偏移了多少。
对于类型为id或其他对象类型的实例变量,请调用object_getIvarobject_setIvar,而不要使用此偏移量直接访问实例变量数据。

例:
    Ivar title0Ivar = class_getInstanceVariable(self.class, "_title0");
    const char *title0Name = ivar_getName(title0Ivar);
    const char *title0Type = ivar_getTypeEncoding(title0Ivar);
    ptrdiff_t title0Offset = ivar_getOffset(title0Ivar);
    NSLog(@"%s, %s, %ld", title0Name, title0Type, title0Offset);
输出:
_title0, @"NSString", 864
  • 返回属性的名字。
const char * _Nonnull property_getName(objc_property_t _Nonnull property) 

例子见property_copyAttributeValue

  • 返回属性的attribute字符串。
const char * _Nullable property_getAttributes(objc_property_t _Nonnull property) 

关于attribute,详见runtime中的class_addProperty方法

例子见property_copyAttributeValue

  • 返回属性的attribute数组。
objc_property_attribute_t * property_copyAttributeList(objc_property_t _Nonnull property,
                             unsigned int * _Nullable outCount)

该数组必须由调用方调用free释放。

outCount 指针,保存数组元素的数量。
例子见property_copyAttributeValue

  • 通过attribute名返回属性的attribute的值。
char * _Nullable property_copyAttributeValue(objc_property_t _Nonnull property,
                            const char * _Nonnull attributeName)

attributeName 为下面的name
char * 返回的即为下面的value的copy

typedef struct {
    //attribute名
    const char * _Nonnull name;       
    //attribute值
    const char * _Nonnull value;      
} objc_property_attribute_t;
例:
    objc_property_t title0Property = class_getProperty(object_getClass(self), "title0");
    const char *title0PropertyName = property_getName(title0Property);
    const char *title0PropertyAttribute = property_getAttributes(title0Property);
    NSLog(@"%s, %s",title0PropertyName, title0PropertyAttribute);
    unsigned int title0PropertyCount = 0;
    objc_property_attribute_t *title0PropertyAttributes = property_copyAttributeList(title0Property, &title0PropertyCount);
    for (NSInteger i = 0; i < title0PropertyCount; i++) {
        objc_property_attribute_t attribute = title0PropertyAttributes[i];
        char *value = property_copyAttributeValue(title0Property, attribute.name);
        NSLog(@"%s, %s, %s", attribute.name, attribute.value, value);
    }
输出:
title0, T@"NSString",&,N,V_title0
T, @"NSString", @"NSString"
&, ,
N, ,
V, _title0, _title0
  • 返回对应名字的协议。
Protocol * _Nullable objc_getProtocol(const char * _Nonnull name)

若找不到名为name的协议,则返回NULL
例子见protocol_getName

  • 返回运行时已知的所有协议的数组。
Protocol * __unsafe_unretained _Nonnull * _Nullable 
objc_copyProtocolList(unsigned int * _Nullable outCount)

您必须使用free释放数组

outCount 指针,保存数组元素的数量。
例子见protocol_getName

  • 判断协议proto是否符合协议other。
BOOL protocol_conformsToProtocol(Protocol * _Nullable proto, Protocol * _Nullable other)

BOOL 若符合,返回YES,否则返回NO。
例子见protocol_getName

  • 判断协议proto和协议other是否相同。
BOOL protocol_isEqual(Protocol * _Nullable proto, Protocol * _Nullable other)

BOOL 若相同,返回YES,否则返回NO。
例子见protocol_getName

  • 返回协议的名字。
const char * _Nonnull protocol_getName(Protocol * _Nonnull proto)
例:
    Protocol *runtimeProtocol = objc_getProtocol("runtimeProtocol");
    const char *runtimeProtocolName = protocol_getName(runtimeProtocol);
    unsigned int allProtocolsCount = 0;
    Protocol * __unsafe_unretained _Nonnull * _Nullable allProtocols = objc_copyProtocolList(&allProtocolsCount);
    NSLog(@"%s %d", runtimeProtocolName, allProtocolsCount);
    Protocol *nsobjectProtocol = objc_getProtocol("NSObject");
    BOOL conform = protocol_conformsToProtocol(runtimeProtocol, nsobjectProtocol);
    BOOL equal = protocol_isEqual(runtimeProtocol, nsobjectProtocol);
    NSLog(@"%@ %@", @(conform), @(equal));

@protocol runtimeProtocol 

@optional
- (void)test;

@end

输出:
runtimeProtocol 3937
1 0
  • 返回协议proto的方法aSel的方法描述结构体。
struct objc_method_description
protocol_getMethodDescription(Protocol * _Nonnull proto, SEL _Nonnull aSel,
                              BOOL isRequiredMethod, BOOL isInstanceMethod)

aSel 协议中方法的选择器
isRequiredMethod 指示方法是否为必需方法
isInstanceMethod 指示方法是否为实例方法
objc_method_description 若协议不包含该方法,则返回{NULL, NULL}。
例子见protocol_copyMethodDescriptionList

  • 返回协议proto的方法描述结构体数组。
objc_method_description * _Nullable
protocol_copyMethodDescriptionList(Protocol * _Nonnull proto,
          BOOL isRequiredMethod, BOOL isInstanceMethod,unsigned int * _Nullable outCount)

不包括该协议符合的其他协议中的方法。
你必须调用free释放该数组。

outCount 指针,保存数组元素的数量。

例:
    Protocol *runtimeProtocol = objc_getProtocol("runtimeProtocol");
    struct objc_method_description testDescription = protocol_getMethodDescription(runtimeProtocol, NSSelectorFromString(@"test"), NO, YES);
    NSLog(@"%@ %s", NSStringFromSelector(testDescription.name), testDescription.types);
    unsigned int descriptionListCount = 0;
    struct objc_method_description *descriptionList = protocol_copyMethodDescriptionList(runtimeProtocol, NO, YES, &descriptionListCount);
    NSLog(@"%d", descriptionListCount);
    for (NSInteger i = 0; i < descriptionListCount; i++) {
        struct objc_method_description description = descriptionList[i];
        NSLog(@"%@ %s", NSStringFromSelector(description.name), description.types);
    }

@protocol runtimeProtocol 

@optional
- (void)test;
- (void)test1;

@end
输出:
test v16@0:8
2
test1 v16@0:8
test v16@0:8
  • 返回协议proto的对应名字的属性。
objc_property_t _Nullable
protocol_getProperty(Protocol * _Nonnull proto,
                     const char * _Nonnull name,
                     BOOL isRequiredProperty, BOOL isInstanceProperty)

name 属性的名字
isRequiredProperty 是否为必须属性
isInstanceProperty 是否为实例属性
objc_property_t 若没有符合的属性,则返回NULL。
例子见protocol_copyPropertyList2

  • 返回协议proto的必需实例属性的数组。
objc_property_t _Nonnull * _Nullable
protocol_copyPropertyList(Protocol * _Nonnull proto,
                          unsigned int * _Nullable outCount)

等效于protocol_copyPropertyList2(proto, outCount, YES, YES)
您必须使用free释放数组。

outCount 指针,保存数组元素的数量。
例子见protocol_copyPropertyList2

  • 返回协议proto的属性数组。
objc_property_t _Nonnull * _Nullable
protocol_copyPropertyList2(Protocol * _Nonnull proto,
                           unsigned int * _Nullable outCount,
                           BOOL isRequiredProperty, BOOL isInstanceProperty)

您必须使用free释放数组。

outCount 指针,保存数组元素的数量。
isRequiredProperty 是否为必须属性
isInstanceProperty 是否为实例属性
objc_property_t * 若协议没有对应的属性,则返回NULL。

例:
    Protocol *runtimeProtocol = objc_getProtocol("runtimeProtocol");
    objc_property_t phoneNum = protocol_getProperty(runtimeProtocol, "phoneNum", YES, YES);
    NSLog(@"%s", property_getName(phoneNum));
    unsigned int propertyListCount = 0;
    (void)protocol_copyPropertyList(runtimeProtocol, &propertyListCount);
    NSLog(@"%d", propertyListCount);
    objc_property_t *propertyList = protocol_copyPropertyList2(runtimeProtocol, &propertyListCount, YES, YES);
    NSLog(@"%d", propertyListCount);
    for (NSInteger i = 0; i < propertyListCount; i++) {
        objc_property_t property = propertyList[i];
        NSLog(@"%s", property_getName(property));
    }
    free(propertyList);

@protocol runtimeProtocol 

@optional
- (void)test;
- (void)test1;

@property (nonatomic, strong) NSString *phoneNum;
@property (nonatomic, strong) NSString *name;

@end
输出:
phoneNum
2
2
phoneNum
name
  • 返回协议proto符合的协议数组。
Protocol * __unsafe_unretained _Nonnull * _Nullable
protocol_copyProtocolList(Protocol * _Nonnull proto,
                          unsigned int * _Nullable outCount)

您必须使用free释放数组。

outCount 指针,保存数组元素的数量。

例:
    unsigned int copyProtocolListCount = 0;
    Protocol * __unsafe_unretained _Nonnull *copyProtocolList = protocol_copyProtocolList(runtimeProtocol, ©ProtocolListCount);
    NSLog(@"%d", copyProtocolListCount);
    for (NSInteger i = 0; i < copyProtocolListCount; i++) {
        Protocol * __unsafe_unretained _Nonnull property = copyProtocolList[i];
        const char *name = protocol_getName(property);
        NSLog(@"%s", name);
    }
    free(copyProtocolList);

@protocol runtimeProtocol 

@end
输出:
1
NSObject
  • 创建一个新的协议实例。
Protocol * _Nullable objc_allocateProtocol(const char * _Nonnull name) 

新的协议需要调用objc_registerProtocol注册后才能使用

name 协议的名字
Protocol * 返回成功的Protocol实例,如果已经存在相同名称的协议,则返回nil。
例子见protocol_addProperty

  • 注册一个新的协议。
void objc_registerProtocol(Protocol * _Nonnull proto) 

proto 通过objc_allocateProtocol创建
例子见protocol_addProperty

  • 向正在构建的协议添加方法。
void protocol_addMethodDescription(Protocol * _Nonnull proto, SEL _Nonnull name,
        const char * _Nullable types,BOOL isRequiredMethod, BOOL isInstanceMethod) 

正在构建中,即objc_allocateProtocolobjc_registerProtocol之间的状态

proto 正在构建中的协议
name 方法的选择器
types 方法的参数类型字符 详情可见runtime的class_addMethod方法
isRequiredMethod 是否为必须方法
isInstanceMethod 是否为实例方法
例子见protocol_addProperty

  • 向正在构建的协议添加要符合的协议。
void protocol_addProtocol(Protocol * _Nonnull proto, Protocol * _Nonnull addition) 

正在构建中,即objc_allocateProtocolobjc_registerProtocol之间的状态

proto 正在构建的协议。
addition proto要符合的协议,必须已经构建。
例子见protocol_addProperty

  • 向正在构建的协议添加属性。
void protocol_addProperty(Protocol * _Nonnull proto, const char * _Nonnull name,
                     const objc_property_attribute_t * _Nullable attributes,
                     unsigned int attributeCount,
                     BOOL isRequiredProperty, BOOL isInstanceProperty)

正在构建中,即objc_allocateProtocolobjc_registerProtocol之间的状态

name 属性的名字
attributes 属性的attributes 详见runtime的class_addProperty方法
attributeCount attributes元素的个数
isRequiredProperty 是否为必须属性
isInstanceProperty 是否为实例属性 YES是该属性唯一允许的情况,若将此属性设置为NO则不会将该属性添加到协议。

例:
    Protocol *testProtocol = objc_allocateProtocol("testProtocol");
    protocol_addMethodDescription(testProtocol, NSSelectorFromString(@"getName"), "v@:", NO, YES);
    protocol_addProtocol(testProtocol, runtimeProtocol);
    objc_property_attribute_t adressAttribute0 = {"T", [[NSString stringWithFormat:@"@\"%@\"", @"NSString"] UTF8String]};//属性的类型 T表示type
    objc_property_attribute_t adressAttribute1 = {"&", ""};//&表示strong C表示copy N表示nonatomic 其他的请自行查看
    objc_property_attribute_t adressAttribute2 = {"N", ""};
    objc_property_attribute_t adressAttribute3  = {"V", [[NSString stringWithFormat:@"_%@", @"adress"] UTF8String]};//属性的名字
    objc_property_attribute_t adressAttrs[] = {adressAttribute0, adressAttribute1, adressAttribute2, adressAttribute3};
    protocol_addProperty(testProtocol, "adress", adressAttrs, 4, YES, YES);
    objc_registerProtocol(testProtocol);
相当于创建了下面的协议
@protocol testProtocol 

- (void)getName;

@property (nonatomic, strong) NSString *adress;

@end

你可能感兴趣的:(runtime.h(四))